Time Complexity for the given Tree Recursion problem - recursion

I was looking at the first Recursive solution for this problem on Leetcode. Here is the code for the proposed solution.
public boolean isSymmetric(TreeNode root) {
return isMirror(root, root);
}
public boolean isMirror(TreeNode t1, TreeNode t2) {
if (t1 == null && t2 == null) return true;
if (t1 == null || t2 == null) return false;
return (t1.val == t2.val)
&& isMirror(t1.right, t2.left)
&& isMirror(t1.left, t2.right);
}
The part of the solution that I do not understand is why the writer of the solution says the time complexity is O(n). Let's say I had the input:
1
/ \
2 2
This is how I trace the call stack in this case:
isMirror(1, 1)
(t1.val == t2.val) returns true
isMirror(2, 2) returns true
(t1.val == t2.val) returns true
isMirror(null, null) return true
isMirror(null, null) return true
isMirror(2, 2) returns true
(t1.val == t2.val) returns true
isMirror(null, null) return true
isMirror(null, null) return true
In the call stack above, isMirror() is called 7 times while n is 3. For the time complexity to be O(n), should isMirror() have only been called 3 times? Or am I looking at this the wrong way? Is it the fact that the call stack only went 3 levels deep that shows that the time complexity is O(n)?
Thank you for the help.

You call the mirror on the null nodes too. So your elements are actually not 3 they are 7. Think the next level on the binary tree and you will see.
Solutions;
Try to check the nullity before calling the function.
it will be still constant factor to your cost. Approximately 2 times. By big O rules you are still O(n).

Related

difference between a == 10 || 20 and a == 10 || a == 20 these two

let s = 10;
if(s == 10 || s == 20){
console.log(s)
}
if( s == 10 || 20){
console.log(s)
}
// What is the defrence between these two conditions
I tried both condition and the output were the same. So what's the difference between them. It may be the stupid question but i want to konw the difference. Thanks in advance
In the first one IF (s == 10 || s == 20) the entire IF condition is TRUE if either boolean expression s == 10 OR s == 20 is TRUE. As this is processed, once the first boolean expression is TRUE the condition is met so the s==10 triggered that and console.log(s) was called.
In the second condition ( s == 10 || 20) the entire condition is TRUE if either boolean expression s==10 OR 20 is TRUE. It succeeds for the same reason as stated above. Typically a non-zero value means TRUE so in your programming language having a value of twenty there is the same as if you had the keyword TRUE there so no syntax error was thrown, even though it really does not make any sense and is indeed a logic error in the code (assuming you meant it to work the same as the first example).
This is why code reviews are a good idea.

sum function in Julia is giving error if the array is empty

I am trying to create a code which identifies if the elements in an array are monotonic or not.
I wrote the below code and got the error -
function isMonotonic(array)
if length(array) <= 2
return true
end
check_up = []
check_down = []
for i in range(2, length(array))
if array[i] <= array[i-1]
append!(check_up, 1)
end
if array[i] >= array[i - 1]
append!(check_down, 1)
end
end
if sum(check_up) == length(array) - 1 || sum(check_down) == length(array) - 1
return true
else
return false
end
end
isMonotonic([1, 2, 3, 4, 5, 6 , 7])
I am getting the below error
Error: Methoderror: no method matching zero(::Type{Any})
I think it is because I am trying to sum up the empth array, I want to understand how to overcome this problem in general, I have a solution for the above code, but in genral I want to know the reason and how to use it. I do not want to first check if the array is empty or not and then do the sum.
If you wanted to save yourself lots of effort, the simplest solution would just be:
my_ismonotonic(x) = issorted(x) || issorted(x ; rev=true)
This will return true if x is sorted either forwards, or in reverse, and false otherwise.
We could maybe make it a little more efficient using a check so we only need a single call to issorted.
function my_ismonotonic(x)
length(x) <= 2 && return true
for n = 2:length(x)
if x[n] > x[1]
return issorted(x)
elseif x[n] < x[1]
return issorted(x ; rev=true)
end
end
return true
end
# Alternatively, a neater version using findfirst
function my_ismonotonic(x)
length(x) <= 2 && return true
ii = findfirst(a -> a != x[1], x)
isnothing(ii) && return true # All elements in x are equal
if x[ii] > x[1]
return issorted(x)
else
return issorted(x ; rev=true)
end
end
The loop detects the first occurrence of an element greater than or less than the first element and then calls the appropriate issorted as soon as this occurs. If all elements in the array are equal then the loop runs over the whole array and returns true.
There are a few problems of efficiency in your approach, but the reason you are getting an actual error message is because given the input, either this expression sum(check_up) or this expression sum(check_down) will effectively result in the following call:
sum(Any[])
There is no obvious return value for this since the array could have any type, so instead you get an error. If you had used the following earlier in your function:
check_up = Int[]
check_down = Int[]
then you shouldn't have the same problem, because:
julia> sum(Int[])
0
Note also that append! is usually for appending a vector to a vector. If you just want to add a single element to a vector use push!.

How to handle (x,1) base case for is_power(x,y) function, where x != 1?

Title says most of it. Here is a related thread, but I do not have enough reputation to comment.
Here is the prompt:
A number, a, is a power of b if it is divisible by b and a/b is a power of b. Write a function called is_power that takes parameters a and b and returns True if a is a power of b.
In the archived post, the most upvoted answer was to address the trivial base cases of (x,x) and (1,x). Then, determine if (a % b == 0) and then recursively call to find (a/b is a power of b).
Here is the code I've written in Julia:
function ispower(a,b)
if a == 0 && b != 0
return false
elseif a == b
return true
elseif a % b == 0 && ispower(a/b, b)
return true
else
return false
end
end
As I wrote in the comment if you multiply 1 by 1 you can only get 1, so the only number that is a power of 1 is 1 and no other number. Therefore, your function should return false for an input (x,1), whenever x is not 1.
Then you should also consider the case where b==0. Then the only number that is a power of b is 0.
So, I would write you function like this:
function ispower(a::Integer,b::Integer)
if (a==b)
return true
elseif (a==0 || b==0 || b==1)
return false
elseif (a % b) == 0
return ispower(div(a,b), b)
else
return false
end
end

Recursion without executing all methods on each recursive call

What's the term for when a recursive algorithm doesn't always reach all functions on each level? Consider this code:
function f(value):
if val < -10 return g(value + 1)
if var > 10 return h(value - 1)
else return 0
function g(value):
if value % 2 == 0 return f(value / 2)
else return h(value)
function h(value):
if value % 2 == 1 return g(value - 1)
else return h(value - 1)
Each recursive call may call a different function such as when we start with 15:
f(15)
h(14)
h(13)
g(12)
f(6)
return 0
I've never heard of a specific term for what you describe, it's simply referred to as recursion.
The fact that it executes potentially different pathways for certain levels of recursion doesn't really make it special, any more than the same feature in a loop:
for i = 1 to 10:
if i is even:
print i, " is even"
else:
print i, " is odd"
That's still called a loop (not something like "alternating loop" or "iteration dependent behavioural loop"). It's similar to your recursion example.
In fact, recursion always has different behaviour at at least one level (the last one) since, without that, it would recur forever and you would most likely overflow the stack.

SML: Basic Prime Testing

I'm trying to write a basic function to take an integer and evaluate to a bool that will check whether the integer is a prime or not.
I've used an auxiliary function to keep track of the current divisor I'm testing, like so:
fun is_divisible(n : int, currentDivisor : int) =
if currentDivisor <= n - 1 then
n mod currentDivisor = 0 orelse is_divisible(n, currentDivisor + 1)
else
true;
fun is_prime(n : int) : bool =
if n = 2 then
true
else
not(is_divisible(n, 2));
It looks right to me but I test it on 9 and get false and then on 11 and get false as well.
Sorry for all the questions today and thanks!
The problem is that if your is_divisible reaches the last case it should return false because it means that all the iterated divisors have resulted in a remainder larger than zero except for the last one which is the number it self. So you should rename is_divisible and return false instead of true

Resources