I was doing a bit of Leetcode and do not understand why res.append(subset) does not append the subset to res.
Could somebody explain the reason behind this?
def solve(arr):
res = []
def dfs(arr,subset):
if len(arr) == 0:
# why does the following line not append the subset to res?
res.append(subset)
for i in range(len(arr)):
subset.append(arr[i])
dfs(arr[:i] + arr[i+1:],subset)
subset.pop()
dfs(arr,[])
return res
Your problem is that you have assumed that res.append(subset) will append the items in subset. Python assignments for compound objects behave differently and so appending a list to a list is not the same as appending the values of a list to a list.
In this example, subset.pop() is removing values from subset and hence res, so that finally solve returns a list of empty lists. To make minimal changes to your code, I suggest that you copy the data using copy.deepcopy().
import copy
def solve(arr):
res = []
def dfs(arr,subset):
if len(arr) == 0:
# copy, rather than reference
res.append(copy.deepcopy(subset))
for i in range(len(arr)):
subset.append(arr[i])
dfs(arr[:i] + arr[i+1:],subset)
subset.pop()
dfs(arr,[])
return res
More information is available in the docs and there are simple examples in previous SO answers
Related
def rev(n):
for i in range(int(len(n)//2)):
temp = n[i]
n[i] = n[len(n)-i-1]
n[len(n)-i-1] = temp
or,n[i], n[len(n)-i-1] = n[len(n)-i-1], n[i]
return n
n=[34,45,56,67]
print(rev(n))
Above code doesn't reverse the list even the logic is correct still the output is same as input.
Can anyone help me with that as i am little bit confused.
The intention appears to be to reverse the contents of a list in situ.
The most common way to do this is to create a new list with:
mylist[::-1]
...then... copy over the original like this:
mylist[:] = mylist[::-1]
However, the intent appears to be to use a custom loop to reverse in place.
def rev(_list):
i, j = 0, len(_list)
while (j := j - 1) > i:
_list[i], _list[j] = _list[j], _list[i]
i += 1
return _list
This demonstrates the correct element swap syntax and also obviates the need to create a new list. It is however very slow in comparison to traditional techniques
I believe that a similar question has been asked for Java but I'm not sure whether the same applies to Python since we don't explicitly use the new keyword
For this particular code:
x = 5
while (x > 0):
arr = []
arr2 = []
arr.append(1)
arr2.append(2)
x -= 1
After executing this code, will there be a total of 10 different lists being created, which is a space complexity of O(10), or will there only be 2 lists being created, which is a space complexity of O(2).
I understand the overall space complexity is still O(1) but just wanted to find out what happens under the hood.
Firstly, since you wrote arr = [] inside the while loop it will rewrite the previous array, hence both arr and arr2 will have at most 1 element
Secondly, with the formal definition of Big-O complexity O(1) and O(2) are considered the same constant-complexity, Big-O complexity is meant to be used with a variable to capture complexity relative to a variable.
If you want to know whether or not python creates a new array with your code, you can override the default list object to log it's operations:
class ilist(list):
def __init__(self, r=list()):
print("Making new list: " + str(r))
list.__init__(self, r)
def __del__(self):
print("Deleting list")
x = 5
while (x > 0):
arr = ilist()
arr2 = []
arr.append(1)
arr2.append(2)
x -= 1
print("Finished while")
output:
Making new list: []
Making new list: []
Deleting list
Making new list: []
Deleting list
Making new list: []
Deleting list
Making new list: []
Deleting list
Finished while
Deleting list
and as you can see it indeed creates and deletes the array every time since that array is created and used only inside the block of while.
But it behaves as it should, if your intention was to create it once, then you should declare it in the outer scope.
I'm new to recursion and finding it pretty difficult to grasp. I can't figure out how to append an empty array if I can't directly "touch" it. If its a string I would add the value each time. If it was a number that involved multiplication, I could multiply it each time, but with an array, I don't know what to do.
I dont know how to append to an empty array without being able to directly "touch" it.
This is what I've done so far:
def laugh(num):
if num == 0:
return []
# This doesnt work since we can't append a function call. I'm unsure what to do.
return laugh(num - 1).append("ha ")
print(laugh(3)) -> ["ha, ha, ha"]
If could do this easily if i could just return a string of "Ha"'s instead. I could return an empty string and just add a "Ha" for each step.
You can modify it like:
def laugh(num):
if num == 0:
return []
haha = laugh(num-1)
haha.append("ha")
return haha
Since append does not return the modified list, you have to do it in two steps. Using concatenation and the ternary operator, you can shrink this to:
def laugh(num):
return laugh(num-1) + ["ha"] if num else []
In this case you are mutating the list by calling append on it. What you want to do is return a new list:
def laugh(num):
# base case
if num == 0:
return []
# recursive case
return ["ha"] + laugh(num-1)
Consider the following piece of code that generates all subsets of size k of an array [1,2,3,...,n]:
def combinations(n, k):
result = []
directed_combinations(n, k, 1, [], result)
return result
def directed_combinations(n, k, offset, partial_combination, result):
if len(partial_combination) == k:
new_partial = [x for x in partial_combination]
result.append(new_partial)
return
num_remaining = k - len(partial_combination)
i = offset
# kind of checks if expected num remaining is no greater than actual num remaining
while i <= n and num_remaining <= n - i + 1:
partial_combination.append(i)
directed_combinations(n, k, i + 1, partial_combination, result)
del partial_combination[-1]
# partial_combination = partial_combination[:-1] <-- same funcationality as line above, but produces weird bug.
i += 1
print(combinations(n=4,k=2))
For example, combinations(n=4,k=2) will generate all subsets of length 2 of [1,2,3,4].
There are two lines in the code that produce a list with the last element removed. I tried accomplishing it with del and creating a brand new list by slicing off the last element (i.e. [-1]). The version with del produces the correct result. But, version with [-1] doesn't. There is no runtime error; just a logical bug (i.e. incorrect result).
I suspect this has something to do with creating a new list when doing slicing vs. keeping the same list with del. I can't seem to understand why this is an issue.
I didn't notice at first that your function is recursive (should've read your tags better).
You're right, functionally the two are almost the same. Here is the exact same thing:
# del partial_combination[-1] # working (mutate)
# partial_combination = partial_combination[:-1] # different (rebind)
partial_combination[:] = partial_combination[:-1] # same (mutate)
The result of each of the above will be that you end up with a list containing the same elements. But while del and partial_combination[:] mutate your original list, the middle one rebinds the name to a new list with the same elements. When you pass on this new list to the next recursive step, it will operate on its own copy rather than on the single list the previous recursive levels are working on.
To prove this, you can call print(id(partial_combination)) after each of the above options, and see that the id changes in the rebinding case, while it stays the same throughout the mutating ones.
I found this code online.
def quick_sort(items):
""" Implementation of quick sort """
if len(items) > 1:
pivot_index = len(items) / 2
smaller_items = []
larger_items = []
for i, val in enumerate(items):
if i != pivot_index:
if val < items[pivot_index]:
smaller_items.append(val)
else:
larger_items.append(val)
quick_sort(smaller_items)
quick_sort(larger_items)
items[:] = smaller_items + [items[pivot_index]] + larger_items
The one line that gives me trouble is the last one. I believe it's basic concatenation, however, when I change "items[:]" to "items", the algorithm fails. What is special about the [:] at the end of the list?
If anyone one can help, I would really appreciate. Thank you in advance!
This is in-place assignment, without replacing the list object with a new object.
This way, the output is placed in the original list and can be read by the caller.