Algorithm to check matching parenthesis - algorithm

This relates to the Coursera Scala course so I want to directly ask you NOT to give me the answer to the problem, but rather to help me debug why something is happening, as a direct answer would violate the Coursera honor code.
I have the following code:
def balance(chars: List[Char]): Boolean = {
val x = 0
def loop(list: List[Char]): Boolean = {
println(list)
if (list.isEmpty) if(x == 0) true
else if (list.head == '(') pushToStack(list.tail)
else if (list.head == ')') if(x <= 0) false else decreaseStack(list.tail)
else loop(list.tail)
true
}
def pushToStack(myList: List[Char]) { x + 1; loop(myList)}
def decreaseStack(myList: List[Char]) { x - 1; loop(myList)}
loop(chars)
}
A simple explanation:
If the code sees a "(" then it adds 1 to a variable. If it sees a ")" then it first checks whether the variable is equal to or smaller than 0. If this is the case, it returns false. If the value is bigger than 0 then it simply decreases one from the variable.
I have tried running the following:
if(balance("This is surely bad :-( ) (".toList)) println("balanced") else println("not balanced");
Clearly this is not balanced, but my code is returning balanced.
Again: I am not asking for help in writing this program, but rather help in explained why the code is returning "balanced" when clearly the string is not balanced
--EDIT--
def balance(chars: List[Char]): Boolean = {
val temp = 0;
def loop(list: List[Char], number: Int): Boolean = {
println(list)
if (list.isEmpty) if(number == 0) true
else if (list.head == '(') loop(list.tail, number + 1)
else if (list.head == ')') if(number <= 0) false else loop(list.tail, number - 1)
else loop(list.tail,number)
true
}
loop(chars,0)
}
^^ Still prints out balanced

You are using an immutable x when you really want a mutable x.
Here, let me rewrite it for you in a tail recursive style to show you what you're actually doing:
#tailrec def loop(myList: List[Char], cur: Int = 0): Boolean = myList match{
case "(" :: xs =>
val tempINeverUse = cur+1
loop(xs, cur) //I passed in 0 without ever changing "cur"!
case ")" :: xs if cur < 0 => false //This is a bug, regardless if you fix the rest of it
case ")" :: xs =>
val tempINeverUse = cur-1
loop(xs, cur) //Passed in 0 again!
case x :: xs => loop(xs, cur)
case Nil => cur == 0 //Since I've never changed it, it will be 0.
}

You need to keep a context of parenthesis in comments or in quotes as well. You can use a counter to achieve that. If the counter is set for a comment or a double quote then ignore any parenthesis that comes your way. Reset the counter whenever you find a finishing comment or double quote

Related

Understanding operation algorithm for PseudoCode

Algo(A,p,r,k)
ret = false
if(p <= r) then
if(p = r) then
ret = (k == A[p])
else
q = (p+r)/2
ret = (k == A[q]) || Algo(A,p,q - 1,k)
if(ret = false)
ret = Algo(A,q+1,r,k)
return ret
please explain to me what operation it does in line 11 ret = (k == A[q]) || Algo(A,p,q - 1,k)??
I can’t understand the meaning of that OR without any matching construct.
thanks in advance
Usually (but you need to check what your teacher is able to say), || is a short-cut or operator. Short-cut in the sense that (for or) if the left expression is true then you don't have to evaluate the right one because you can deduce the result of the full boolean expression.

How not get out of bound in Kotlin?

I got the code that compare current element with the next element in array. But it crashes with out of bound because I guess when its on the last element there is no next element to compare with so it crashes.How to handle this to avoid crash and stop comparing on the last element? Here is my code
fun myFunction(arr: Array<Int>): Int{
if (arr.isEmpty()) return 0
var result = 0
for (item in arr.indices) {
if (arr[item] > 0 && arr[item + 1] < 0){
result ++
}
if (arr[item] < 0 && arr[item + 1] > 0){
result ++
}
}
return result
}
The direct answer to your question:
Instead of
for (item in arr.indices)
you should write
for (item in 0..(arr.lastIndex - 1))
Explanation: arr.indices returns the range 0..arr.lastIndex but in the loop you are checking the element after the current index; therefore you should only go up to arr.lastIndex - 1.
Some further advice:
IntArray is more efficient than Array<Int>
You can combine the two if statements into one using the || (or) operator.
If you are counting the number of sign changes, you need to consider how to interpret 0. In your code, an input of [1,-1] would give a result of 1 sign change, but [1,0,-1] would give 0, which seems wrong. To fix that, treat 0 as positive:
if ((arr[item] >= 0 && arr[item + 1] < 0) || arr[item] < 0 && arr[item + 1] >= 0) {
result++
}
You don't need to check if the array is empty; just remove that line. The loop won't be entered if the array is empty or if it has only 1 element.
Finally, you can use some cool features of the standard libray (look them up in the documentation to learn them) which can make your function succinct:
fun myFunction(arr: IntArray): Int {
var result = 0
arr.asList().zipWithNext().forEach { (a, b) ->
if ((a >= 0 && b < 0) || (a < 0 && b >= 0))
result++
}
return result
}
and even more succinct still:
fun myFunction(arr: IntArray) =
arr.asList().zipWithNext().count { (a, b) -> (a >= 0) != (b >= 0) }
References: single-expression functions, zipWithNext, count, destructuring.

Recursive solution to common longest substring between two strings

I am trying to return the length of a common substring between two strings. I'm very well aware of the DP solution, however I want to be able to solve this recursively just for practice.
I have the solution to find the longest common subsequence...
def get_substring(str1, str2, i, j):
if i == 0 or j == 0:
return
elif str1[i-1] == str2[j-1]:
return 1 + get_substring(str1, str2, i-1, j-1)
else:
return max(get_substring(str1, str2, i, j-1), get_substring(str1, str2, j-1, i))
However, I need the longest common substring, not the longest common sequence of letters. I tried altering my code in a couple of ways, one being changing the base case to...
if i == 0 or j == 0 or str1[i-1] != str2[j-1]:
return 0
But that did not work, and neither did any of my other attempts.
For example, for the following strings...
X = "AGGTAB"
Y = "BAGGTXAYB"
print(get_substring(X, Y, len(X), len(Y)))
The longest substring is AGGT.
My recursive skills are not the greatest, so if anybody can help me out that would be very helpful.
package algo.dynamic;
public class LongestCommonSubstring {
public static void main(String[] args) {
String a = "AGGTAB";
String b = "BAGGTXAYB";
int maxLcs = lcs(a.toCharArray(), b.toCharArray(), a.length(), b.length(), 0);
System.out.println(maxLcs);
}
private static int lcs(char[] a, char[] b, int i, int j, int count) {
if (i == 0 || j == 0)
return count;
if (a[i - 1] == b[j - 1]) {
count = lcs(a, b, i - 1, j - 1, count + 1);
}
count = Math.max(count, Math.max(lcs(a, b, i, j - 1, 0), lcs(a, b, i - 1, j, 0)));
return count;
}
}
You need to recurse on each separately. Which is easier to do if you have multiple recursive functions.
def longest_common_substr_at_both_start (str1, str2):
if 0 == len(str1) or 0 == len(str2) or str1[0] != str2[0]:
return ''
else:
return str1[0] + longest_common_substr_at_both_start(str1[1:], str2[1:])
def longest_common_substr_at_first_start (str1, str2):
if 0 == len(str2):
return ''
else:
answer1 = longest_common_substr_at_both_start (str1, str2)
answer2 = longest_common_substr_at_first_start (str1, str2[1:])
return answer2 if len(answer1) < len(answer2) else answer1
def longest_common_substr (str1, str2):
if 0 == len(str1):
return ''
else:
answer1 = longest_common_substr_at_first_start (str1, str2)
answer2 = longest_common_substr(str1[1:], str2)
return answer2 if len(answer1) < len(answer2) else answer1
print(longest_common_substr("BAGGTXAYB","AGGTAB") )
I am so sorry. I didn't have time to convert this into a recursive function. This was relatively straight forward to compose. If Python had a fold function a recursive function would be greatly eased. 90% of recursive functions are primitive. That's why fold is so valuable.
I hope the logic in this can help with a recursive version.
(x,y)= "AGGTAB","BAGGTXAYB"
xrng= range(len(x)) # it is used twice
np=[(a+1,a+2) for a in xrng] # make pairs of list index values to use
allx = [ x[i:i+b] for (a,b) in np for i in xrng[:-a]] # make list of len>1 combinations
[ c for i in range(len(y)) for c in allx if c == y[i:i+len(c)]] # run, matching x & y
...producing this list from which to take the longest of the matches
['AG', 'AGG', 'AGGT', 'GG', 'GGT', 'GT']
I didn't realize getting the longest match from the list would be a little involved.
ls= ['AG', 'AGG', 'AGGT', 'GG', 'GGT', 'GT']
ml= max([len(x) for x in ls])
ls[[a for (a,b) in zip(range(len(ls)),[len(x) for x in ls]) if b == ml][0]]
"AGGT"

Algorithms, DFS

I've written a program to find shortest path in a N*N grid recursively.
def dfs(x,y,Map,p):
N = len(Map)
p += [[x,y]]
if Map[x][y] == 'E':
return p
for i in [[x-1,y],[x+1,y],[x,y-1],[x,y+1]]:
if N > i[0] >= 0 and N > i[1] >= 0 :
if (Map[i[0]][i[1]] == 'P' or Map[i[0]][i[1]] == 'E') and i not in p:
dfs(i[0], i[1], Map,p)
return []
When Map[x][y] = 'E' the recursion don't stop and return p. But it goes till the end. How to correct it and return the path(p).
By the looks of it, the code is prone to loop indefinitely. This is due to lack of checks whether you've entered a node before and moving in all (4) directions from a given node.
To solve it simply, add another array NxN of Boolean values answering the question: visited?. Then update the code to something along the lines:
def dfs(x,y,Map,visited,p):
visited[x,y] = true;
N = len(Map)
(...)
if (Map[i[0]][i[1]] == 'P' or Map[i[0]][i[1]] == 'E')
and i not in p
and visited[i[0], i[1]] == false:
dfs(i[0], i[1], Map,visited,p)

Algorithm to determine if a range contains a case-insensitive search phrase?

Let's say you have thousands of files organized in the following way: First you sort them by their filename (case sensitive, so that upper case files come before lower case), then you grouped them into folders that contain the name of the first and the last file in that folder. E.g., the folders may look like:
Abel -> Cain
Camel -> Sloth
Stork -> basket
basking -> sleuth
tiger -> zebra
Now, given a case-insensitive search string s, determine which folders that can contain a file that matches s. You cannot and do not have to look inside a folder - the file does not actually have to exist.
Some examples:
("Abel", "Cain") matches s = "blue", since it contains "Blue"
("Stork", "basket") matches s = "arctic", since it contains "arctic"
("FA", "Fb") matches s = "foo", since it contains "FOo"
("Fa", "Fb") does NOT match s = "foo"
Formally: Given a closed range [a,b] and a lower case string s, determine if there's any string c in [a,b] such that lower(c) = s.
My first hunch was to do a case-insensitive search against the bounds of the range. But it can be easily seen from the last example that this is not correct.
A bruce-force solution is to generate all potential file names. For example, the input string "abc" would produce the candidates "ABC", "ABc", "AbC", "Abc", "aBC", "aBc", "abC", "abc". Then you just test each against the bounds. An example of this brute-force solution will follow below. This is O(2^n) though.
My question is if there's an algorithm for this that is both fast and correct?
Brute-force solution in Clojure:
(defn range-contains
[first last string]
(and (<= (compare first string) 0)
(>= (compare last string) 0)))
(defn generate-cases
"Generates all lowercase/uppercase combinations of a word"
[string]
(if (empty? string)
[nil]
(for [head [(java.lang.Character/toUpperCase (first string))
(java.lang.Character/toLowerCase (first string))]
tail (generate-cases (rest string))]
(cons head tail))))
(defn range-contains-insensitive
[first last string]
(let [f (fn [acc candidate] (or acc (range-contains first last (apply str candidate))))]
(reduce f false (generate-cases string))))
(fact "Range overlapping case insensitive"
(range-contains-insensitive "A" "Z" "g") => true
(range-contains-insensitive "FA" "Fa" "foo") => true
(range-contains-insensitive "b" "z" "a") => false
(range-contains-insensitive "B" "z" "a") => true)
I think that instead of creating all the upper-lower case combinations, this can be solved by checking upper, then lower for each character separately, which changes 2^N into 2N.
The idea is the following:
keep "lowdone" and "highdone" flags, which indicate whether s can definitely come after the low limit while still potentially coming before the high limit, and vice versa
go character by character through the string
check if the uppercase version of the current letter can come after the corresponding low limit letter while at the same time coming before the high limit letter, then check the same for the lowercase version of the letter, if neither letter satisfies both conditions, return false (don't check low limit if "lowdone" is true, don't check high limit if "highdone" is true - when comparing ABC and ACA, once we are past the second letter, we don't care about the third letter)
if a case satisfies both conditions, check if it comes strictly after the low limit letter or the low limit is too short to have a corresponding letter, if so, lowdone = true
analogous for highdone = true
Does this sound good? Code in C# (could probably be written more concisely):
public Bracket(string l, string u)
{
Low = l;
High = u;
}
public bool IsMatch(string s)
{
string su = s.ToUpper();
string sl = s.ToLower();
bool lowdone = false;
bool highdone = false;
for (int i = 0; i < s.Length; i++)
{
char[] c = new char[]{su[i], sl[i]};
bool possible = false;
bool ld = lowdone;
bool hd = highdone;
for (int j = 0; j < 2; j++)
{
if ((lowdone || i >= Low.Length || c[j] >= Low[i]) && (highdone || i >= High.Length || c[j] <= High[i]))
{
if (i >= Low.Length || c[j] > Low[i])
ld = true;
if (i >= High.Length || c[j] < High[i])
hd = true;
possible = true;
}
}
lowdone = ld;
highdone = hd;
if (!possible)
return false;
}
if (!lowdone && Low.Length > s.Length)
return false;
return true;
}
}
In the spirit of full disclosure, I guess I should also add the algorithm I came up with (Java, uses Guava):
public static boolean inRange(String search, String first, String last) {
int len = search.length();
if (len == 0) {
return true;
}
char low = Strings.padEnd(first, len, (char) 0).charAt(0);
char high = Strings.padEnd(last, len, (char) 0).charAt(0);
char capital = Character.toLowerCase(search.charAt(0));
char small = Character.toUpperCase(search.charAt(0));
if (low == high) {
if (capital == low || small == low) {
// All letters equal - remove first letter and restart
return inRange(search.substring(1), first.substring(1), last.substring(1));
}
return false;
}
if (containsAny(Ranges.open(low, high), capital, small)) {
return true; // Definitely inside
}
if (!containsAny(Ranges.closed(low, high), capital, small)) {
return false; // Definitely outside
}
// Edge case - we are on a bound and the bounds are different
if (capital == low || small == low) {
return Ranges.atLeast(first.substring(1)).contains(search.substring(1).toLowerCase());
}
else {
return Ranges.lessThan(last.substring(1)).contains(search.substring(1).toUpperCase());
}
}
private static <T extends Comparable<T>> boolean containsAny(Range<T> range, T value1, T value2) {
return range.contains(value1) || range.contains(value2);
}

Resources