I know there is a O(n) time complexity solution for this problem, here for example.
I am just curious why my naive approach in O(2^n) is not working in Python.
Algorithm:
I am just finding the permutations recursively and when the kth element is added, i am returning it. However I get the return result as None. I am not sure why None is returned by my function.
class Solution(object):
# Time complexity O(2 ^ n)
def getPermutation(self, n, k):
char_list = map(str, range(1, n + 1)) #convert to strin
used = [False] * len(char_list)
result = []
kthArray = self._getPermutation_helper(result, char_list, used, [], k)
print kthArray #kthArray is always None
def _getPermutation_helper(self, result, char_list, used, cur, k):
if len(char_list) == len(cur):
result.append(cur + [])
print len(result)
print cur
if len(result) == k:
print "cur in kth is {0}".format(cur)
return cur #cur is printed correctly but not returned
for i in range(len(char_list)):
if not used[i]:
cur.append(char_list[i])
used[i] = True
self._getPermutation_helper(result, char_list, used, cur, k)
# back track
used[i] = False
cur.remove(char_list[i])
def main():
pgm = Solution()
pgm.getPermutation(3, 6)
if __name__ == "__main__":
main()
Why isn't the correct value returned?
Because you are returning cur to a previous call of the same function, from which you don't return it further down to the first call.
You need to keep propagating the found solution until the first call. For example:
for i in range(len(char_list)):
if not used[i]:
cur.append(char_list[i])
used[i] = True
# Here we do a recursive call, which might find the answer we're looking for.
# So we save its return value and, if it's not None, we return it.
r = self._getPermutation_helper(result, char_list, used, cur, k)
if r is not None:
return r
Related
I am trying to reverse the array in groups but I am getting this error:
:---- for i in arr: TypeError: 'NoneType' object is not iterable.
What's wrong with my code?
def reverseSubarray(arr,n,k):
if k == 1:
return
i = 0
while i < n:
l = i
r = min(i+k-1, n-1)
while l < r:
temp = arr[l]
arr[l] = arr[r]
arr[r] = temp
l += 1
r -= 1
i += k
return arr
def main():
n = int(input().strip())
string = input().strip().split()
arr=[]
for j in string:
arr.append(int(j.strip()))
k=int(input().strip())
arr = reverseSubarray(arr,n,k)
for i in arr:
print(i,end=' ')
if __name__ == "__main__":
main()
So the problem is that you're actually returning None. This happens because most likely you're giving k=1 so it will go to that line where you return nothing, which will return this error when trying to iterate.
You can treat the problem with a try-catch block on arr=reverseSubarray(arr,n,k) that will return a message like k cannot be 1
You can reverse an array in groups in python as given below,
def reverseSubarray(arr, N, K):
for i in range(0, len(arr),K):
l=arr[i:i+K]
l.reverse()
arr[i:i+K] =l
return arr
While your error was indeed coming from the fact that your function is returning None as other answers have pointed out, you have also written the function in a very non-pythonic style. Here is an example of how you could rewrite it more succintly:
def reverseInGroups(self, arr, N, K):
for i in range(0, N, K):
arr[i:i+K] = reversed(arr[i:i+K])
return arr
range(0, N, K) will return an iterator that goes from 0 to N-1 in steps of K. In other word, i will successively have value: 0, K, 2K, 3K, 4K, etc. until the last multiple of K that is less than N. Here is the documentation for more details.
arr[i:i+K] will refer to the slice of arr between indices i and i+K-1 or, put another way, [arr[i], arr[i+1], arr[i+2], ..., arr[i+K-1]]. It stops at i+K-1 so that you can naturally use arr[i:i+K] and arr[i+K:] without counting arr[i+K] twice.
reversed... reverses an iterator. Here's the doc.
I wanted to write code such that I could find the k-th largest number using quick-sort and wrote the following in LeetCode, which LeetCode will call upon findKthLargest first
class Solution(object):
def partition(self, arr,left,right):
piv = arr[right]
i = left-1
counter = left
while (counter<right):
if (arr[counter]<piv):
i = i+1
tmp = arr[counter]
arr[counter]=arr[i]
arr[i]=tmp
counter = counter+1
temp = arr[i+1]
arr[i+1]=arr[right]
print('pivot '+str(piv)+' at '+str(i+1))
arr[right]=temp
print("at the nmoment "+str(arr))
return (i+1)
def helper(self,arr,left,right,k):
if (left>=right):
return
p = self.partition(arr,left,right)
print("p is now "+str(p))
if (p==len(arr)-k):
return int(arr[p])
self.helper(arr,left,p-1,k)
self.helper(arr,p+1,right,k)
def findKthLargest(self, nums, k):
f= self.helper(nums,0,len(nums)-1,k)
print(f)
I've even printed (arr[p]) INSIDE the helper method and it gave me the correct answer however inside of the method findKthLargest the variable f shows up as a none type and I was wondering where did I go wrong? At the moment I believe that it is returning a none type since inside of the recursive loops when checking if (left>=right) inside of the helper method it returns none
The problem is that your helper function does not always return a value. Only in the base case, where the if condition is true, it will return a numeric value. But it should also return that same number where the corresponding recursive calls are made.
So change:
self.helper(arr,left,p-1,k)
self.helper(arr,p+1,right,k)
to:
result = self.helper(arr,left,p-1,k)
if result is not None:
return result
return self.helper(arr,p+1,right,k)
This way the deepest return value will bubble up the recursion tree, and a success in the first recursive call will avoid that the second recursive call is made.
Hard to debug your code, this'd pass though with less statements:
class Solution:
def findKthLargest(self, nums, k):
def kth_smallest(nums, k):
if nums:
pos = partition(nums, 0, len(nums) - 1)
if k > pos + 1:
return kth_smallest(nums[pos + 1:], k - pos - 1)
elif k < pos + 1:
return kth_smallest(nums[:pos], k)
else:
return nums[pos]
def partition(nums, left, right):
res = left
while left < right:
if nums[left] < nums[right]:
nums[left], nums[res] = nums[res], nums[left]
res += 1
left += 1
nums[res], nums[right] = nums[right], nums[res]
return res
return kth_smallest(nums, len(nums) + 1 - k)
I have the following code. It's about as simple as I can make it. Does anyone know of a slick way to turn this recursion into a loop?
The problem is that I can run into a recusion limit. I've thought of some ways to rewrite it, but they're not pretty at all.
My nicest thought at this point is that I could get it into some tail recursion form, but I'm not sure how to do that.
def blackbox(c, i): #This is a different function in production
if i > 5:
return range(0,1)
else:
return range(0,c+i)
def recurse(c, length):
if length == 0:
return [[]]
return [l + [j] for j in blackbox(c, length) for l in recurse(c - j, length - 1)]
Example: recurse(6, 1000) throws an error is way over the recursion limit.
Cool, mostly useless fact: Using range(i, c + 1) for the black box returns all the lists with length length with sum at most c.
EDIT: I'm aware I can memoize the code, but that doesn't fix recursion limit. In this example, memoizing helps the speed a lot, but in my situation it doesn't, so I'm not concerned with it.
EDIT 2: Updated blackbox so the value of recurse(6,1000) is reasonable.
One way can be to use your own stack of generator functions instead:
def blackbox(c, i):
return range(0, c + i) #This code is actually quite different, treat it as a black box
# For testing at the end
def recurse(c, length):
if length == 0:
return [[]]
return [l + [j] for j in blackbox(c, length) for l in recurse(c - j, length - 1)]
# Non-recursive variant following:
gen_stack = []
def gen_driver():
prevResult = None
while gen_stack:
try:
if prevResult is not None:
gen_stack[-1].send(prevResult)
prevResult = None
else:
next(gen_stack[-1])
except StopIteration as si:
prevResult = si.value
del gen_stack[-1]
return prevResult
def nonrecurse(c, length):
if length == 0:
return [[]]
# Unfortunately the concise list comprehension doesn't work
result = []
for j in blackbox(c, length):
gen_stack.append(nonrecurse(c - j, length - 1))
for l in (yield):
result.append(l + [j])
return result
gen_stack.append(nonrecurse(6, 10))
# Testing equality of both variants
print(gen_driver() == recurse(6,10))
# No crash but I didn't wait until it was ready
gen_stack.append(nonrecurse(6, 1000))
Slightly shorter variant but needs more care:
gen_stack = []
def gen_driver():
prevResult = None
while gen_stack:
try:
if prevResult is not None:
gen_stack.append(gen_stack[-1].send(prevResult))
prevResult = None
else:
gen_stack.append(next(gen_stack[-1]))
except StopIteration as si:
prevResult = si.value
del gen_stack[-1]
return prevResult
def single_generator(value):
return value
yield # Mark it as generator function
def nonrecurse(c, length):
if length == 0:
return single_generator([[]])
return [l + [j] for j in blackbox(c, length) for l in (yield nonrecurse(c - j, length - 1))]
gen_stack.append(nonrecurse(6, 10))
# Testing equality of both variants
print(gen_driver() == recurse(6,10))
While in the first variant nonrecurse was a generator function, it is now a usual function returning generators where the list comprehension is a generator on its own.
My problem is on my second function code.
This is my code so far....
def simi(d1,d2):
dna_1 = d1.lower()
dna_2 = d2.lower()
lst = []
i = 0
while i < len(dna_1):
if dna_1[i] == dna_2[i]:
lst.append(1)
i += 1
return len(lst) / len(d1)
def match(list_1, d , s):
dna = []
for item in list_1:
dna.append(simi(item, d))
if max(dna) < s:
return None
return list_1[max(dna)]
You have two problems, the first is you return in the loop before you have tried all the elements, secondly your function simi(item, d)returns a float if it works correctly so trying to index a list with a float will also fail. There is no way your code could do anything but error or return None.
I imagine you want to keep track of the best each iteration and return the item that is the best based on what it's simi distance calc is and if the simi is > s or else return None:
def match(list_1, d , s):
best = None
mx = float("-inf")
for item in list_1:
f = simi(item, d)
if f > mx:
mx = f
best = item
return best if mx > s else None
You can also use range in simi instead of your while loop with a list comp:
def simi(d1,d2):
dna_1 = d1.lower()
dna_2 = d2.lower()
lst = [1 for i in range(len(dna_1)) if dna_1[i] == dna_2[i] ]
return len(lst) / len(dna_1)
But if you just want to add 1 each time they condition is True you can use sum:
def simi(d1,d2):
dna_1 = d1.lower()
dna_2 = d2.lower()
sm = sum(dna_1[i] == dna_2[i] for i in range(len(dna_1)))
return sm / len(dna_1)
Using some builtins:
from functools import partial
similarity_with_sample = partial(simi, 'TACgtAcGaCGT')
Now similarity_with_sample is a function that takes one argument, and returns its similarity with 'TACgtAcGaCGT'.
Now use that as the key argument of the builtin max function:
best_match = max(list_of_samples, key=similarity_with_sample)
I'm not sure what your s variable is doing.
I am attempting to implement heap sort using the psuedo code from the book Intro to Algorithms. The following is what I have:
def parent(i):
return i/2
def left(i):
return 2*i
def right(i):
return 2*i+1
def max_heapify(seq, i, n):
l = left(i)
r = right(i)
if l <= n and seq[n] > seq[i]:
largest = l
else:
largest = i
if r <= n and seq[r] > seq[largest]:
largest = r
if largest != i:
seq[i], seq[largest] = seq[largest], seq[i]
max_heapify(seq, largest, n)
def heap_length(seq):
return len(seq) - 1
def build_heap(seq):
n = heap_length(seq)
for i in range(n/2,0,-1):
max_heapify(seq, i, n)
def sort(seq):
build_heap(seq)
heap_size = heap_length(seq)
for i in range(heap_size,1,-1):
seq[1], seq[i] = seq[i], seq[1]
heap_size = heap_size - 1
max_heapify(seq, 1, heap_size)
return seq
I am having issues with understanding passing by value or by reference in Python. I have looked at the following question and it seems that I am passing the list by value. My questions is how to return the correctly sorted list either by reference or by value?
arrays are always passed by reference
if you want to pass by value use slice
my_func(my_array[:]) #send copy
my_func(my_array) #array is modified inside and changes are reflected in original