How do I calculate the complexity of this leetcode solution? - python

I worked on on this problem on Leetcode called numbers-with-same-consecutive-differences and have no idea why the runtime for this solution (and many others in the discussion section of that problem) is O(2^N).
class Solution:
def numsSameConsecDiff(self, N, K):
"""
:type N: int
:type K: int
:rtype: List[int]
"""
ans = list(range(1, 10))
for _ in range(N-1):
temp = []
for n in ans:
prev = n % 10
if K == 0:
temp.append(10 * n + prev)
else:
if prev >= K:
temp.append(10 * n + prev - K)
if prev + K <= 9:
temp.append(10 * n + prev + K)
ans = temp[:]
return [0] + ans if N == 1 else ans
I get O(N (length of integers in answers) * n (length of answer) * 2 (the two choices in the else case)), and that is far from O(2^n). Where am I misunderstanding things?

Related

Optimizing the closest 3sum solution to avoid time limit exceeded error

I was going through this closest 3-sum leetcode problem which says:
Given an integer array nums of length n and an integer target, find three integers in nums such that the sum is closest to target.
Return the sum of the three integers.
You may assume that each input would have exactly one solution.
I have created the following solution and this appears correct but it fails with the Time Limit Exceeded error. How could I optimize this code? I have already added one of the optimization I felt but not sure how can I improve this further.
class Solution:
def threeSumClosest(self, nums: List[int], target: int) -> int:
nums.sort()
csum = None
min_diff = float("+inf")
for i in range(0,len(nums)-2):
l = i + 1
r = len(nums)-1
if i > 0 and nums[i] == nums[i-1]:
continue # OPTIMIZATION TO AVOID SAME CALCULATION
while l < r:
sum = nums[i] + nums[l] + nums[r]
diff = abs(target-sum)
if sum == target:
csum = target
min_diff = 0
break
elif sum > target:
r -= 1
else:
l += 1
if min_diff > diff:
min_diff = diff
csum = sum
return nums[0] if csum is None else csum
Maybe this reference approach can help: Try it first and see if you have any question. Note - see this from a recent post, it performs really well - exceeds 90% of submission in Python category.
def threeSumClosest(self, nums: List[int], target: int) -> int:
nums.sort()
return self.kSumClosest(nums, 3, target)
def kSumClosest(self, nums: List[int], k: int, target: int) -> int:
N = len(nums)
if N == k: return sum(nums[:k]) # found it
# too small
tot = sum(nums[:k])
if tot >= target: return tot
# too big
tot = sum(nums[-k:])
if tot <= target: return tot
if k == 1:
return min([(x, abs(target - x)) for x in nums], key = lambda x: x[1])[0]
closest = sum(nums[:k])
for i, x in enumerate(nums[:-k+1]):
if i > 0 and x == nums[i-1]:
continue
current = self.kSumClosest(nums[i+1:], k-1, target - x) + x
if abs(target - current) < abs(target - closest):
if current == target:
return target
else:
closest = current
return closest

I am trying to write a function in Python encapsulating the Miller-Rabin primality test, but it is very slow

Here is my code:
import random
def miller(n, k):
"""
takes an integer n and evaluates whether it is a prime or a composite
n > 3, odd integer to be tested for primality
k, rounds of testing (the more tests, the more accurate the result)
"""
temp = n - 1 # used to find r and d in n = 2**d * r + 1, hence temporary
r = 0
while True:
if temp / 2 == type(int):
r += 1
else:
d = temp
break
temp = temp / 2
for _ in range(k):
a = random.SystemRandom().randrange(2, n - 2)
x = a**d % n
if x == 1 or x == n - 1:
continue
for _ in range(r - 1):
x = x**2 % n
if x == n - 1:
continue
return "Composite"
return "Probably prime"
Certainly there must be more effective ways to implement the algorithm in Python, so that it may handle large integers with ease?
Cheers

How to calculate a power of a number with O(log n) complexity?

This is for pure understanding, but i have a code thats basically O(n), but i am unable to decipher how to change it to Olog(n), and each time i use recursion i get nlog(n) complexity.
def power(n,p):
val = []
for i in range(p):
val.append(n)
res = val
n = 1
for x in res:
n*= x
return n
print(power(2,8)) # returns 256
what i need is a code that does the exact same as this above code but it basically does it in Olog(n) as opposed to O(n)
This code implements power() with complexity O(log(n)):
def power(x, y):
if y==0:
return 1
n = power(x, y // 2)
if y % 2 == 0:
return n * n
else:
if y > 0:
return x * n * n
else:
return (n * n) / x

Find three Numbers with Sum closest to a given number

I am trying to solve a problem where,
Given an array S of n integers, find three integers in S such that the
sum is closest to a given number, target. Return the sum of the three
integers. You may assume that each input would have exactly one
solution.
For example, given array S = {-1 2 1 -4}, and target = 1.
The sum that is closest to the target is 2. (-1 + 2 + 1 = 2).
My solution is: take a number out (number_1) from the array, set the target to target - that number and find two other numbers which are closest to the new target. This way: number_1 + number_2 + number_3 will be closest as number_2 + number_3 will be closest to target - number_1.
I tried my solution at https://leetcode.com/problems/3sum-closest/description/.
My solution is:
def threeSumClosest(nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: int
"""
closest_sum = nums[0] + nums[1] + nums[2]
for i in range(len(nums)):
# Create temp array excluding a number
if i!=len(nums)-1:
temp = nums[:i] + nums[i+1:]
else:
temp = nums[:len(nums)-1]
# Sort the temp array and set new target to target - the excluded number
temp = sorted(temp)
l, r = 0, len(temp) -1
t = target - nums[i]
while(l<r):
if temp[l] + temp[r] == t:
return target
elif temp[l] + temp[r] > t:
if abs(temp[l] + temp[r] + nums[i] - target) < abs(closest_sum - target):
closest_sum = temp[l] + temp[r] + nums[i]
r = r - 1
else:
if abs(temp[l] + temp[r] + nums[i] - target) < abs(closest_sum - target):
closest_sum = temp[l] + temp[r] + nums[i]
l = l + 1
return closest_sum
It passes 80 test cases out of 125, so the solution logic looks fine enough for me.
It fails for:
Input:
[0,2,1,-3]
1
Output:
3
Expected:
0
Can't understand why it fails and how to make my logic consistent.
Thanks for your help.
You have couple of mistakes the first one is silly, you have an extra indentation in return closest and the second one is not checking updating closest in the 3rd if statement.
This code got accepted:
class Solution(object):
def threeSumClosest(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: int
"""
closest = nums[0] + nums[1] + nums[2]
#if len(nums)==3:
# return closest
for i in range(len(nums)):
if i!=len(nums)-1:
temp = nums[:i] + nums[i+1:]
else:
temp = nums[:len(nums)-1]
temp = sorted(temp)
l, r = 0, len(temp) -1
t = target - nums[i]
while(l < r):
if abs(temp[l] + temp[r] + nums[i] - target) < abs(closest - target):
closest = temp[l] + temp[r] + nums[i]
if temp[l] + temp[r] == t:
return target
elif temp[l] + temp[r] > t:
r = r - 1
else:
l = l + 1
return closest
And this is an accepted C++ solution with O(n^2) running time:
class Solution {
public:
int threeSumClosest(vector<int>& nums, int target) {
sort(nums.begin(), nums.end());
int ans = nums[0] + nums[1] + nums[2];
for(int i = 0; i < nums.size() - 2; i++) {
int l = i + 1, r = nums.size() - 1;
while (l < r) {
if(abs(nums[i] + nums[l] + nums[r] - target) < abs(target - ans)) {
ans = nums[i] + nums[l] + nums[r];
}
if(nums[r] + nums[l] > target - nums[i]) r = r - 1;
else l = l + 1;
}
}
return ans;
}
};
As we worked out in the comments the last return statment was erroneously inside the for loop cutting it short after the first iteration.
Also, closest should be updated in both branches where we overshoot or undershoot the target.
I think an obvious improvement of your algorithm would be to sort first. Removing individual elements doesn't destroy order, so you'd need to sort only once. That would get you from O(n^2 log n) to O(n^2).
You can find all combinations of values in the list, and then find the listing whose sum is closest to the target:
import itertools
s = [{'vals':[-1, 2, 1, -4], 'target':1}, {'vals':[0,2,1,-3],'target':1}]
final_result = {tuple(a['vals']):sum(min(itertools.combinations(a['vals'], 3), key=lambda x:abs(a['target']-sum(x)))) for a in s}
Output:
{(-1, 2, 1, -4): 2, (0, 2, 1, -3): 0}
My solution works for this input:
[0,2,1,-3]
1
Your closest sum variable is incorrect. See my variable named "gap"
class Solution:
def threeSumClosest(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: int
"""
sorted_nums = sorted(nums)
gap = sorted_nums[len(nums)-1] * 10000
solution = 0
for pointer_1 in range(len(sorted_nums)):
pointer_2 = pointer_1 + 1
pointer_3 = len(sorted_nums) - 1
while(pointer_2 < pointer_3):
gap_n = abs((sorted_nums[pointer_1]+sorted_nums[pointer_2]+sorted_nums[pointer_3]) - target)
add = (sorted_nums[pointer_1]+sorted_nums[pointer_2]+sorted_nums[pointer_3])
if (gap_n < gap):
solution = add
gap = gap_n
elif (target > add):
pointer_2 = pointer_2 + 1
else:
pointer_3 = pointer_3 - 1
return solution

Recursive formula in python for recursive sigma how to?

I recently asked this question and got the first answer. I'm trying to put this into python code. This is what I have, but I keep getting 0 as the answer.
def f(n, k, s):
ans = 0
for j in range(1, min({k,s}) + 1):
print j
if (n == 1):
if (k >= s):
ans = ans + 1
elif (k < s):
ans = ans + 0
elif (s > n):
ans = ans + 0
elif (n*k < s):
ans = ans + 0
else:
ans = ans + f(n-1,j,s-j)
return ans
print f(10, 12, 70)
What is wrong with my code? What do I need to change? I don't know what's wrong. Please help. Thanks!
Your code is way too complex. You can write an almost one-to-one transcription of the answer you got on math exchange:
def f(n, k, s):
if n == 1:
return int(k >= s)
# or: 1 if k >=s else 0
return sum(f(n-1, j, s-j) for j in range(1, min(k, s)+1))
# to make it faster:
#return sum(f(n-1, j, s-j) for j in range(1, min(k, s)+1) if n*k >= s)
The problem in your code is that you put the base-case checking inside the loop, when it should be outside:
def f(n, k, s):
ans = 0
if n == 1:
return int(k >= s)
for j in range(1, min({k,s}) + 1):
print j
if n*k >= s:
ans += f(n-1,j,s-j)
return ans
With both implementations I get 12660 as result for f(10, 12, 70).
I don't know why yours doesn't work, but here's an implementation that does, which IMO is MUCH more readable:
from itertools import permutations
def f(n, k, s):
if k > s:
k = s-1
count = 0
sum_perms = []
number_list = []
for i in range(1,k):
for j in range(1,k,i):
number_list.append(i)
for perm in permutations(number_list, n):
if sum(perm) == s and perm not in sum_perms:
sum_perms.append(perm[:])
count += 1
return sum_perms, count
It's a lot slower than the recursion technique though :-(
itertools is amazing.

Categories

Resources