Complexity of recursive algorithm - algorithm

I have an algorithm, and I would like to find out the complexity of it, but there is recursion, and I don't know how to count with recursion. My code is:
public boolean algorithm(int x, int y) {
if (x == matrixHeight - 1 && matrix1[x][y] == '0') {
return true;
} else if (x == 1 && matrix1[x-1][y] == '0') {
return true;
} else if (y == matrixWidth - 1 && matrix2[x][y] == '0') {
return true;
} else if (y == 1 && matrix2[x][y-1] == '0') {
return true;
}
if (matrix1[x-1][y] == '0' && tempMatrix[x-1][y] == '-'){
path.push(new int[]{x-1, y});
tempMatrix[x-1][y] = '+'
if (!algorithm(x-1, y)) {
path.pop();
} else {
return true;
}
}
if (matrix2[x][y] == '0' && tempMatrix[x][y+1] == '-'){
path.push(new int[]{x, y+1});
tempMatrix[x][y+1] = '+';
if (!algorithm(x, y+1)) {
path.pop();
} else {
return true;
}
}
if (matrix1[x][y] == '0' && tempMatrix[x+1][y] == '-'){
path.push(new int[]{x+1, y});
tempMatrix[x+1][y] = '+';
if (!algorithm(x+1, y)) {
path.pop();
} else {
return true;
}
}
if (matrix2[x][y-1] == '0' && tempMatrix[x][y-1] == '-'){
path.push(new int[]{x, y-1});
tempMatrix[x][y-1] = '+';
if (!algorithm(x, y-1)) {
path.pop();
} else {
return true;
}
}
return false;
}
There, x, y are coordinates in matrix.
matrix1 and matrix2 are two-dimensional arrays that contain '0' or '1'
tempMatrix is a two-dimensional array that contains '+' or '-'
path is a Stack
matrixHeight is matrix1.length
matrixWidth is matrix[0].length
N, M is the size of the matrix (constant)
Note: this is maze solver that uses backtrack.

For recursion, you need to generate a recurrence relation and solve. See http://en.wikipedia.org/wiki/Recurrence_relation. There is no set way to solve every recurrence relation or even to generate one from an algorithm.
An example is with merge sort. Consider how much work is done at each recursive call. First, there is a constant time division; then two recursive calls are made; then there is a linear time merge. How much work does the recursive call take? Well, each one does the same thing, two recursive calls plus linear merge step. So you need an expression for how deep and wide the tree goes. You know for input size of n, the height of the tree is O(log(n)), and at each step a total of O(n) merge work is done, so therefore O(n log(n)) work is done total.

It looks like a depth first maze solver that returns true if you can exit the labyrinth and false otherwise. The complexity is O(lines * columns) because you visit each cell a constant number of times in the worst case.
1 1 1 1
1 0 0 1
0 0 0 1
1 1 1 1
Start at (1, 1). Your algorithm will go up, backtrack, go right, try up again, backtrack, right again, backtrack, then down and so on. For labyrinths constructed like this it looks like your algorithm will spend a lot of time solving them.
In fact, most recursive (depth first to be more accurate) approaches will spend a long time, because it will always be possible to force them to do a maximum number of steps.
Look into the Lee algorithm for a better approach.

There is actually a really simple analysis of the complexity of this algorithm.
Each call to algorithm makes zero to four recursive calls to algorithm and does some constant amount of other work. So, if we can bound the number of times that algorithm is called then we know the complexity. Now, note that just before every call to algorithm (except for the first) you change an element of tempMatrix from '-' to '+'. And so, the number of calls to algorithm is bounded by the size of tempMatrix, and the complexity is O(matrixWidth * matrixHeight).
Another approach (that would be more obvious with more meaningfull variable names) is simply noticing that you are doing a depth-first search on the x-y grid. And so each "square" will be visited once.

Related

Evenly space n items over m iterations

For context, this is to control multiple stepper motors simultaneously in a high-accuracy application.
Problem statement
Say I have a loop that will run i iterations. Over the course of those iterations, expression E_x should evaluate to true x times (x <= i is guaranteed).
Requirements
- E_x must evaluate to true exactly x times
- E_x must evaluate to true at more or less evenly spaced intervals*
* "evenly spaced intervals" means that the maximum interval size is minimized
Examples
For: i = 10, x = 7
E_x will be true on iterations marked 1: 1101101101
For: i = 10, x = 3
E_x will be true on iterations marked 1: 0010010010
For: i = 10, x = 2
E_x will be true on iterations marked 1: 0001000100
What is the best (or even "a good") way to have E_x evaluate to true at evenly spaced intervals while guaranteeing that it is true exactly x times?
This question is close to mine, however it assumes that E_x will always evaluate to true in the 1st and last iterations, which does not meet my requirements (see 2nd example above).
I'll use a bit different naming convention: let's there by T intervals [1..T] and N events to be fired. Also let's solve the problem as a cyclic one. To do the let's add one fake step at the end that we are guaranteed to fire event at (and this will be also the event at time 0 i.e. before the cycle). So my T is your i+1 and my N is your x+1.
If you divide T by N with reminder you'll get T = w*N + r. If r=0 the case is trivial. If r != 0 the best you can achieve is r intervals of size w+1 and (N-r) intervals of size w. The fast and simple but good enough solution would be something like this (pseudocode):
events = []
w = T / N
r = T % N
current = 0
for(i = 1; i<=N; i++) {
current += w;
if (i <= r)
current += 1;
events[i] = current;
}
You can see that the last value in the array will be T as was promised by our re-statement as a cyclic problem. It will be T because over the cycle we'll add w to current N times and add r times 1, so the sum will be w*N+r which is T.
The main drawback of this solution is that all the "long" intervals will be at the start while all the "short" interval will be at the end.
You can spread intervals more evenly if you are a bit smarter. And the resulting logic will be essentially the same as it is behind Bresenham's line algorithm referenced in comments. Imagine you are drawing a line on a plane, where X-axis represents time and Y-axis represents events, from (0,0) (which is the 0-th event, before your timeframe) to (i+1, x+1) (which is the x+1-th event, just after your timeframe). The moment to raise an event is when you switch to the next Y i.e. draw the first pixel at a given Y.
If you want to do x increments over n iterations, you can do it like this:
int incCount = 0;
int iterCount = 0;
boolean step() {
++iterCount;
int nextCount = (iterCount*x + n/2) / n; // this is rounding division
if (nextCount > incCount) {
++incCount;
return true;
}
else {
return false;
}
}
That's the easy-to-understand way. If you're on an embedded CPU where division is more expensive, you can accomplish exactly the same thing like this:
int accum = n/2;
boolean step() {
accum+=x;
if (accum >= n) {
accum-=n;
return true;
}
else {
return false;
}
}
The total amount added to accum here is iterCount*x + n/2 just like the first example, but the division is replaced with an incremental repeated subtraction. This is the way that Bresenham's line drawing algorithm works.

Implementing isPrime in Scala using tail recursion

I'm working on an exercise which requires me to implement isPrime in scala using tail recursion. I do have an implementation however, I'm having issues with producing the right base case.
So my algorithm involves checking all numbers from 2 to N/2, since N/2 would be the largest factor of N.
def isPrime(n: Int): Boolean = {
def isPrimeUntil(t: Int): Boolean = {
if(t == 2) true
else n % t != 0 && isPrimeUntil(t - 1)
}
isPrimeUntil(n/2)
}
So basically if I want to check if 15 is a prime I will check all numbers from 7 to 2.
Here is my trace:
isPrimeUntil(7) -> true && isPrimeUntil(6)
-> true && isPrimeUntil(5)
-> false && isPrimeUntil(4)
Because of short-circuit evaluation, the function returns false at this point.
However, my implementation fails for the basic case of checking if 3 is prime.
3 isn't your only problem. It also returns true for 4 ...
Your base case should be 1, not 2:
def isPrimeUntil(t: Int): Boolean = t == 1 || t > 1 && n%t != 0 && isPrimeUntil(t-1)
Although Krzystof correctly pointed that the source of the problem is integer division, I don't like his solution. I believe that the proper fix is change the test to
if(t <= 2) true
With such check in the case of n = 3 and so n/2 = 1 it will stop without going to t = 0.
Some benefits:
The modified check (t <= 2) on almost any modern hardware is as efficient as the check for (t == 2)
IMHO it better conveys the logic
It is very inefficient way to write (n.toDouble/2).ceil.toInt that way. It's easier and faster to write (n+1)/2 instead of doing 2 conversion (to double and back to int)
It doesn't require an excessive check for all odd n ((n+1)/2 is never the smallest divisor for an odd n where there is a difference between n/2 and ceil(n/2))

Output smallest number k palindrome

With a dynamic programming problem, I am trying to come up with an english algorithm, memo table, best case, and recursive calls to fill the table for the following problem:
Given a string s of length n, design an algorithm that outputs the smallest number k such that s = w1w2 . . . wk where each wi is a palindrome. In other words, find the smallest k such that s can be written as a concatenation of k palindromes. For the definition of a palindrome see practice problems. For example if s = "add" then the algorithm should output k = 2 since we can take w1 ="a" and w2 ="dd". On the other hand, if s = "ada", then the algorithm should output k = 1.
I came up with the following algorithm:
Start
Declare variables s as string, n as integer, k as integer, i as integer.
Initialize k to 1
Read s
n<-length of string s
while i is less then n-1
if s[i]==s[i+1] then
k++
end if
display k
End
However, I am unsure how to come up with the memoization table, best case, and the recursive steps needed to fill the table.
In dynamic programming, memo table saves the answer for the sub problem of the actual problem. Combining these sub problem answer we can calculate the answer for the actual problem.
For this problem, actual problem is to find minimum k palindrome for string s. So, sub problem could be like what is the minimum k for part/substring's of string s. To simplify it, if we know the answer for substring s[0:i] and s[i+1:length(s)-1], then we can calculate the answer for s[0:length(s)-1] = s[0:i] + s[i+1:length(s)-1].
From this we can easily form our recursive relation:
minKPalindrome(start, end) = minKPalindrome(start, i) + minKPalindrome(i+1, end), (start < i < end)
here, minKPalindrome(start, end) is function that return minimum k plaindrome for s[start:end] substring
Possible base cases:
- if start > end , return answer 0
- s[start:end] is palindrome, so return answer is 1
Recursive algorithm:
memo[start][end] = contains answer for s[start:end]
minKPalindrome(start, end) {
if s[start:end] is palindrome {
return 1
}
if ans is already saved in memo[start][end] {
return memo[start][end]
}
memo[start][end] = end - start + 1 // set maximum possible answer
for i = start+1 to end-1 {
memo[start][end] = min( memo[start][end], minKPalindrome(start, i) + minKPalindrome(i+1, end))
}
return memo[start][end]
}
Optimized algorithm:
Generalize previous recursive relation:
minKPalindrome(s[start: end]) = minKPalindrome(s[start, i]) + minKPalindrome(s[i+1, end])
or,
minKPalindrome(s[start: end]) = minKPalindrome(prefix of s) + minKPalindrome(suffix of s)
Instead checking for every prefix of string s, we can just check for only the prefix that are palindrome.
if start[start:i] is palindrome {
minKPalindrome(s[start: end]) = 1 + minKPalindrome(s[i+1:end])
}
base case:
- if start > end, return 0
recursive algorithm:
memo[start] = contains answer for s[start:end]
end = lenght(s) - 1
minKPalindrome(start, end) {
if start > end {
return 0
}
if ans is already saved in memo[start] {
return memo[start]
}
memo[start] = end - start + 1 // set maximum possible answer
for i = start to end {
if s[start:i] is palindrome {
memo[start] = min( memo[start], 1 + minKPalindrome(i+1, end))
}
}
return memo[start]
}
iterative algorithm:
for iterative algorithm we will save answer for for prefix of string s.
memo[i] = contains answer for s[0:i]
for i = 0 to length(s)-1 {
for j= 0 to i {
if s[j:i] is palindrome {
memo[i] = min( memo[i], 1 + memo[j-1])
}
}
}

Probabilistic Sieve of Eratosthenes

Consider the following algorithm.
function Rand():
return a uniformly random real between 0.0 and 1.0
function Sieve(n):
assert(n >= 2)
for i = 2 to n
X[i] = true
for i = 2 to n
if (X[i])
for j = i+1 to n
if (Rand() < 1/i)
X[j] = false
return X[n]
What is the probability that Sieve(k) returns true as a function of k ?
Let's define a series of random variables recursively:
Let Xk,r denote the indicator variable, taking value 1 iff X[k] == true by the end of the iteration in which the variable i took value r.
In order to have fewer symbols and since it makes more intuitive sense with the code, we'll just write Xk,i which is valid although would have been confusing in the definition since i taking value i is confusing when the first refers to the variable in the loop and the latter to the value of the variable.
Now we note that:
P(Xk,i ~ 0) = P(Xk,i-1 ~ 0) + P(Xk,i-1 ~ 1) * P(Xk-1,i-1 ~ 1) * 1/i
(~ is used in place of = just to make it understandable, since = would otherwise take two separate meanings and looks confusing).
This equality holds by virtue of the fact that either X[k] was false at the end of the i iteration either because it was false at the end of the i-1, or it was true at that point, but in that last iteration X[k-1] was true and so we entered the loop and changed X[k] with probability of 1/i. The events are mutually exclusive, so there is no intersection.
The base of the recursion is simply the fact that P(Xk,1 ~ 1) = 1 and P(X2,i ~ 1) = 1.
Lastly, we note simply that P(X[k] == true) = P(Xk,k-1 ~ 1).
This can be programmed rather easily. Here's a javascript implementation that employs memoisation (you can benchmark if using nested indices is better than string concatenation for the dictionary index, you could also redesign the calculation to maintain the same runtime complexity but not run out of stack size by building bottom-up and not top-down). Naturally the implementation will have a runtime complexity of O(k^2) so it's not practical for arbitrarily large numbers:
function P(k) {
if (k<2 || k!==Math.round(k)) return -1;
var _ = {};
function _P(n,i) {
if(n===2) return 1;
if(i===1) return 1;
var $ = n+'_'+i;
if($ in _) return _[$];
return _[$] = 1-(1-_P(n,i-1) + _P(n,i-1)*_P(n-1,i-1)*1/i);
}
return _P(k,k-1);
}
P(1000); // 0.12274162882390949
More interesting would be how the 1/i probability changes things. I.e. whether or not the probability converges to 0 or to some other value, and if so, how changing the 1/i affects that.
Of course if you ask on mathSE you might get a better answer - this answer is pretty simplistic, I'm sure there is a way to manipulate it to acquire a direct formula.

Programming Interview Question / how to find if any two integers in an array sum to zero?

Not a homework question, but a possible interview question...
Given an array of integers, write an algorithm that will check if the sum of any two is zero.
What is the Big O of this solution?
Looking for non brute force methods
Use a lookup table: Scan through the array, inserting all positive values into the table. If you encounter a negative value of the same magnitude (which you can easily lookup in the table); the sum of them will be zero. The lookup table can be a hashtable to conserve memory.
This solution should be O(N).
Pseudo code:
var table = new HashSet<int>();
var array = // your int array
foreach(int n in array)
{
if ( !table.Contains(n) )
table.Add(n);
if ( table.Contains(n*-1) )
// You found it.;
}
The hashtable solution others have mentioned is usually O(n), but it can also degenerate to O(n^2) in theory.
Here's a Theta(n log n) solution that never degenerates:
Sort the array (optimal quicksort, heap sort, merge sort are all Theta(n log n))
for i = 1, array.len - 1
binary search for -array[i] in i+1, array.len
If your binary search ever returns true, then you can stop the algorithm and you have a solution.
An O(n log n) solution (i.e., the sort) would be to sort all the data values then run a pointer from lowest to highest at the same time you run a pointer from highest to lowest:
def findmatch(array n):
lo = first_index_of(n)
hi = last_index_of(n)
while true:
if lo >= hi: # Catch where pointers have met.
return false
if n[lo] = -n[hi]: # Catch the match.
return true
if sign(n[lo]) = sign(n[hi]): # Catch where pointers are now same sign.
return false
if -n[lo] > n[hi]: # Move relevant pointer.
lo = lo + 1
else:
hi = hi - 1
An O(n) time complexity solution is to maintain an array of all values met:
def findmatch(array n):
maxval = maximum_value_in(n) # This is O(n).
array b = new array(0..maxval) # This is O(1).
zero_all(b) # This is O(n).
for i in index(n): # This is O(n).
if n[i] = 0:
if b[0] = 1:
return true
b[0] = 1
nextfor
if n[i] < 0:
if -n[i] <= maxval:
if b[-n[i]] = 1:
return true;
b[-n[i]] = -1
nextfor
if b[n[i]] = -1:
return true;
b[n[i]] = 1
This works by simply maintaining a sign for a given magnitude, every possible magnitude between 0 and the maximum value.
So, if at any point we find -12, we set b[12] to -1. Then later, if we find 12, we know we have a pair. Same for finding the positive first except we set the sign to 1. If we find two -12's in a row, that still sets b[12] to -1, waiting for a 12 to offset it.
The only special cases in this code are:
0 is treated specially since we need to detect it despite its somewhat strange properties in this algorithm (I treat it specially so as to not complicate the positive and negative cases).
low negative values whose magnitude is higher than the highest positive value can be safely ignored since no match is possible.
As with most tricky "minimise-time-complexity" algorithms, this one has a trade-off in that it may have a higher space complexity (such as when there's only one element in the array that happens to be positive two billion).
In that case, you would probably revert to the sorting O(n log n) solution but, if you know the limits up front (say if you're restricting the integers to the range [-100,100]), this can be a powerful optimisation.
In retrospect, perhaps a cleaner-looking solution may have been:
def findmatch(array num):
# Array empty means no match possible.
if num.size = 0:
return false
# Find biggest value, no match possible if empty.
max_positive = num[0]
for i = 1 to num.size - 1:
if num[i] > max_positive:
max_positive = num[i]
if max_positive < 0:
return false
# Create and init array of positives.
array found = new array[max_positive+1]
for i = 1 to found.size - 1:
found[i] = false
zero_found = false
# Check every value.
for i = 0 to num.size - 1:
# More than one zero means match is found.
if num[i] = 0:
if zero_found:
return true
zero_found = true
# Otherwise store fact that you found positive.
if num[i] > 0:
found[num[i]] = true
# Check every value again.
for i = 0 to num.size - 1:
# If negative and within positive range and positive was found, it's a match.
if num[i] < 0 and -num[i] <= max_positive:
if found[-num[i]]:
return true
# No matches found, return false.
return false
This makes one full pass and a partial pass (or full on no match) whereas the original made the partial pass only but I think it's easier to read and only needs one bit per number (positive found or not found) rather than two (none, positive or negative found). In any case, it's still very much O(n) time complexity.
I think IVlad's answer is probably what you're after, but here's a slightly more off the wall approach.
If the integers are likely to be small and memory is not a constraint, then you can use a BitArray collection. This is a .NET class in System.Collections, though Microsoft's C++ has a bitset equivalent.
The BitArray class allocates a lump of memory, and fills it with zeroes. You can then 'get' and 'set' bits at a designated index, so you could call myBitArray.Set(18, true), which would set the bit at index 18 in the memory block (which then reads something like 00000000, 00000000, 00100000). The operation to set a bit is an O(1) operation.
So, assuming a 32 bit integer scope, and 1Gb of spare memory, you could do the following approach:
BitArray myPositives = new BitArray(int.MaxValue);
BitArray myNegatives = new BitArray(int.MaxValue);
bool pairIsFound = false;
for each (int testValue in arrayOfIntegers)
{
if (testValue < 0)
{
// -ve number - have we seen the +ve yet?
if (myPositives.get(-testValue))
{
pairIsFound = true;
break;
}
// Not seen the +ve, so log that we've seen the -ve.
myNegatives.set(-testValue, true);
}
else
{
// +ve number (inc. zero). Have we seen the -ve yet?
if (myNegatives.get(testValue))
{
pairIsFound = true;
break;
}
// Not seen the -ve, so log that we've seen the +ve.
myPositives.set(testValue, true);
if (testValue == 0)
{
myNegatives.set(0, true);
}
}
}
// query setting of pairIsFound to see if a pair totals to zero.
Now I'm no statistician, but I think this is an O(n) algorithm. There is no sorting required, and the longest duration scenario is when no pairs exist and the whole integer array is iterated through.
Well - it's different, but I think it's the fastest solution posted so far.
Comments?
Maybe stick each number in a hash table, and if you see a negative one check for a collision? O(n). Are you sure the question isn't to find if ANY sum of elements in the array is equal to 0?
Given a sorted array you can find number pairs (-n and +n) by using two pointers:
the first pointer moves forward (over the negative numbers),
the second pointer moves backwards (over the positive numbers),
depending on the values the pointers point at you move one of the pointers (the one where the absolute value is larger)
you stop as soon as the pointers meet or one passed 0
same values (one negative, one possitive or both null) are a match.
Now, this is O(n), but sorting (if neccessary) is O(n*log(n)).
EDIT: example code (C#)
// sorted array
var numbers = new[]
{
-5, -3, -1, 0, 0, 0, 1, 2, 4, 5, 7, 10 , 12
};
var npointer = 0; // pointer to negative numbers
var ppointer = numbers.Length - 1; // pointer to positive numbers
while( npointer < ppointer )
{
var nnumber = numbers[npointer];
var pnumber = numbers[ppointer];
// each pointer scans only its number range (neg or pos)
if( nnumber > 0 || pnumber < 0 )
{
break;
}
// Do we have a match?
if( nnumber + pnumber == 0 )
{
Debug.WriteLine( nnumber + " + " + pnumber );
}
// Adjust one pointer
if( -nnumber > pnumber )
{
npointer++;
}
else
{
ppointer--;
}
}
Interesting: we have 0, 0, 0 in the array. The algorithm will output two pairs. But in fact there are three pairs ... we need more specification what exactly should be output.
Here's a nice mathematical way to do it: Keep in mind all prime numbers (i.e. construct an array prime[0 .. max(array)], where n is the length of the input array, so that prime[i] stands for the i-th prime.
counter = 1
for i in inputarray:
if (i >= 0):
counter = counter * prime[i]
for i in inputarray:
if (i <= 0):
if (counter % prime[-i] == 0):
return "found"
return "not found"
However, the problem when it comes to implementation is that storing/multiplying prime numbers is in a traditional model just O(1), but if the array (i.e. n) is large enough, this model is inapropriate.
However, it is a theoretic algorithm that does the job.
Here's a slight variation on IVlad's solution which I think is conceptually simpler, and also n log n but with fewer comparisons. The general idea is to start on both ends of the sorted array, and march the indices towards each other. At each step, only move the index whose array value is further from 0 -- in only Theta(n) comparisons, you'll know the answer.
sort the array (n log n)
loop, starting with i=0, j=n-1
if a[i] == -a[j], then stop:
if a[i] != 0 or i != j, report success, else failure
if i >= j, then stop: report failure
if abs(a[i]) > abs(a[j]) then i++ else j--
(Yeah, probably a bunch of corner cases in here I didn't think about. You can thank that pint of homebrew for that.)
e.g.,
[ -4, -3, -1, 0, 1, 2 ] notes:
^i ^j a[i]!=a[j], i<j, abs(a[i])>abs(a[j])
^i ^j a[i]!=a[j], i<j, abs(a[i])>abs(a[j])
^i ^j a[i]!=a[j], i<j, abs(a[i])<abs(a[j])
^i ^j a[i]==a[j] -> done
The sum of two integers can only be zero if one is the negative of the other, like 7 and -7, or 2 and -2.

Resources