What is python pass by reference not working? - python

I have a solution for generating permutations of an array which is as follows:
class Solution:
def permuteHelper(self,li,nums,ji,x):
if len(ji)==x:
li.append(ji)
return
for i in range(len(nums)):
ji.append(nums[i])
self.permuteHelper(li,nums[:i]+nums[i+1:],ji,x)
ji.pop()
def permute(self, nums: List[int]) -> List[List[int]]:
li = []
ji = []
self.permuteHelper(li,nums,ji,len(nums))
return li
Idea is to use another array that appends each element from original array one by one skipping before appended elements. But when doing it like this, I am getting an output of list of empty lists.
Online I saw someone do the same except they did it like this:
class Solution:
def permuteHelper(self,li,nums,ji,x):
if len(ji)==x:
li.append(ji)
return
for i in range(len(nums)):
self.permuteHelper(li,nums[:i]+nums[i+1:],ji+[nums[i]],x)
def permute(self, nums: List[int]) -> List[List[int]]:
li = []
ji = []
self.permuteHelper(li,nums,ji,len(nums))
return li
I have no idea why their solution worked and mine did not, I had the same logic as theirs but I don't understand the difference. Can someone please explain why the second one worked and the first one did not?

Related

Comparing time complexity for two solutions for same python problem statement

We have first solution as :
class Solution:
def containsDuplicate(self, nums: List[int]) -> bool:
return len(nums) != len(set(nums))
Ans second approach for the same problem as :
class Solution(object):
def containsDuplicate(self, nums):
hset = set()
for idx in nums:
if idx in hset:
return True
else:
hset.add(idx)
Question : Both having time complexity equal to O(N), but actual time taken has major difference between two approaches. Why is this the case ?

Get all elements of nested lists with recursion

~ from This Edabit Challenge ~
I need to get all the elements of nested lists and put them all in one list using recursion.My code below prints out each element, but how do I save them all to one list and return them?
It has to be kept in the scope of the function. I can't add a global list and append all of them. It works technically, but it doesn't work for the challenge I'm trying to pass.
I printed the values out (which is var x in the code) because that shows me that I'm getting close (I think). I just need a way to return the values back to my function and have it append it to the list that I will eventually return.
Examples:
flatten([[[[[["direction"], [372], ["one"], [[[[[["Era"]]]], "Sruth", 3337]]], "First"]]]]) ➞ ["direction", 372, "one", "Era", "Sruth", 3337, "First"]
flatten([[4666], [5394], [466], [[["Saskia", [[[[["DXTD"]], "Lexi"]]]]]]]) ➞ [4666, 5394, 466, "Saskia", "DXTD", "Lexi"]
Code:
def flatten(arr):
res = []
if isinstance(arr, list):
for i in arr:
res.append(flatten(i))
else:
return arr
if isinstance(res, list):
for i in res:
x = flatten(i)
if x:
print(x)
x = flatten([[[[[["direction"], [372], ["one"], [[[[[["Era"]]]], "Sruth", 3337]]], "First"]]]])
print(main)
outputs :
direction
372
one
Era
Sruth
3337
First
[]
The output above shows that my code goes through every non-list value.
Variations of Hai Vu's solutions...
Their first solution uses nested generators, meaning every value gets yielded through that stack of generators. If the structure is deeply nested, this can make the solution take quadratic instead of linear time overall. An alternative is to create a local list in the main function and have the helper function fill it. I prefer using a nested function for that, so I don't have to pass the list around and don't expose the helper function to the outside.
def flatten(nested):
flat = []
def helper(nested):
for e in nested:
if isinstance(e, list):
helper(e)
else:
flat.append(e)
helper(nested)
return flat
Benchmark with 800 integers at depth 800:
26.03 ms Hai_Vu
0.25 ms Kelly
25.62 ms Hai_Vu
0.24 ms Kelly
26.07 ms Hai_Vu
0.24 ms Kelly
Their second solution uses a "queue" (but really treats it like a "reversed" stack, extending/popping only on the left). I think an ordinary stack (using a list) is more natural and simpler:
def flatten(nested):
stack = [nested]
out = []
while stack:
e = stack.pop()
if isinstance(e, list):
stack += reversed(e)
else:
out.append(e)
return out
Pass a list to flatten, and append to it at each step:
def flatten(arr, list_):
if isinstance(arr, list):
for i in arr:
flatten(i, list_)
else:
list_.append(arr)
test = [['a'], 'b']
output = []
flatten(test, output)
output
['a', 'b']
EDIT: If you want specifically to return the list, use
def flatten(arr, list_=None):
if list_ is None:
list_ = []
if isinstance(arr, list):
for i in arr:
flatten(i, list_)
else:
list_.append(arr)
return list_
I would like to offer two solutions: the first uses recursion and the second uses a queue.
First solution
def flatten_helper(nested):
for e in nested:
if isinstance(e, list):
yield from flatten_helper(e)
else:
yield e
def flatten(nested):
return list(flatten_helper(nested))
The flatten_helper function is a generator, which generates a list of elements that are not a list. If an element is a list, we call flatten_helper again until we get non-list elements.
Second solution
import collections
def flatten(nested):
queue = collections.deque(nested)
out = []
while queue:
e = queue.popleft()
if isinstance(e, list):
queue.extendleft(reversed(e))
else:
out.append(e)
return out
In this solution, we loop through the nested list. If the element is a list, we place each sub element into a queue for later processing. If the element is not a list, we append it to out.
Another possibility... more on the same wavelength of Hai Vu 1st solution:
def flatter(lst):
output = []
for i in lst:
if isinstance(i, list):
output.extend(flatter(i))
else:
output.append(i)
return output

Max sum from a contiguous array(having atleast one element)

Given a list. I have to create sublists having at least one element, and then return the sublist having maximum sum.
here is what I tried :
class Solution:
def maxSubArray(self, nums: List[int]) -> int:
lists=[[]]
for i in range(1,len(nums)+1):
for j in range(1,i):
lists.append(nums[j:i])
new_list=lists
sum_list=[]
for k in range(1,len(new_list)):
sum1=sum(new_list[k])
sum_list.append(sum1)
return max(sum_list)
this is giving this error :
ValueError: max() arg is an empty sequence
How do I tweek my code to remove the empty sublist.
You can check if the list is empty before applying the max() method like this:
class Solution:
def maxSubArray(self, nums: List[int]) -> int:
lists=[[]]
for i in range(1,len(nums)+1):
for j in range(1,i):
lists.append(nums[j:i])
new_list=lists
sum_list=[]
for k in range(1,len(new_list)):
sum1=sum(new_list[k])
sum_list.append(sum1)
if sum_list:
return max(sum_list)
else:
return 0 # or some default value you want

Linked List and array

I know StackOverflow isn't writing the question and getting the answer site but here is my problem from leetcode.
l1 = input()
l2 = input()
def f(x): #Gives reversed of linkedlist ex. [2, 4, 3] return 342
a, u = 0, 0
for ele in x:
if ele.isnumeric():
a += int(ele)*(10**u)
u += 1
return a
l = list(int(i) for i in str(f(l1) + f(l2)))
print(list(reversed(l)))
This question is leet code problem so here I have solved the problem but this is something different they do not want spaces between the number after comma.
Input: [2,4,3]
[5,6,4]
My output:
[7, 0, 8]
Expected output: [7,0,8]
However, I also tried
k = str(f(l1) + f(l2))
print("[" + ",".join(str(k)[::-1]) + "]")
You aren't supposed to use input() and print() on leetcode
When you start a problem they give you a function you have to fill and return the result.
class Solution:
def addTwoNumbers(self, l1: Optional[ListNode], l2: Optional[ListNode]) -> Optional[ListNode]:
#put your code here
return the_result
This problem is supposed to use a linked list with nodes defined as
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
this is what should be the input of the addTwoNumbers() method you are supposed to code.
But somehow by using input() you are bypassing this and grabbing the raw list.
Also, prints(stdout) are not what is being evaluated by the leetcode system, they look for the output of addTwoNumbers() which in this case is blank.
Here is the complete solution;
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def __init__(self):
self.head = None
def rev(self, ls):
res = []
self.head = ls
while self.head:
res.append(str(self.head.val))
self.head = self.head.next
return list(reversed(res))
def addTwoNumbers(self, l1: Optional[ListNode], l2: Optional[ListNode]) -> Optional[ListNode]:
res1 = int(''.join(self.rev(l1)))
res2 = int(''.join(self.rev(l2)))
res3 = str(res1 + res2)
resls = list(reversed([i for i in res3]))
self.head = ListNode(resls[0], None)
finalres = self.head
for i in range(1, len(resls)):
lsn = ListNode(resls[i], None)
finalres.next = lsn
finalres = finalres.next
return self.head
**Explanation**:
I will asume that you know the basics of linked lists i.e, what are they (in case you have confusion please comment).
So in the Solution class, i simply defined a self.head attribute inside its __init__ method which i am going to use to keep track of elements in a linked list. It is initially set to None as right there we don't have any data there.
Then i defined a rev method to reverse the given linked list.
Inside the rev, i created an empty list res to store the data from the linked lists provided.
Rev also takes a linked list as an argument as i will take the data from it and append it to the res list
So i put self.head equal to that linked list ls provided when we call the method.
Then i simply ran a while loop until self.head is defined (i.e, until it is not None which means there is still data).
After every iteration, i kept changing self.head to self.head.next to move forward in the linked list and grab the data from every node of that linked list and append that to res list.
At the end i simply returned the reversed res.
Then i defined another method, addTwoNumbers which takes two linked lists and returns there sum as per the requirement.
First of all i need those two linked lists to be in integer form and reversed ( as per condition). So i used the rev method to reverse them, join method (inbuilt method in python to join a list of strings) to convert the list to string and then int method to convert the string to int.
I did the same with both of the linked lists and stored them in res1 and res2 respectively.
Then i took their sum (res3) and converted it to string as we cannot iterate over an integer .
Then i converted the res3 to a reversed list .
Now the last step, return the whole thing as a listnode.
So i simply created an instance of ListNode;
self.head = ListNode(resls[0], None)
This will create an instance of ListNode with data as first element of resls and next as none.
Then i stored it inside another variable to refrence to the same instance and don't change it.
Then ran a far loop on the remaining elements and kept adding data and next.
Hope you understood. Thanks.
That is just the default representation of a list, it has a space after each comma
x = [1, 2, 3]
print(x) # [1, 2, 3] type is list
print(str(x).replace(" ", "")) # [1,2,3] type is str

Leetcode Contains Duplicate: Hash table confusion

I'm trying to teach myself DS+A but struggling with some questions.
https://leetcode.com/problems/contains-duplicate/
For this question, the first approach that came in my head was hash tables. I know you can do a one liner with sets, but I want to try using hash tables.
class Solution:
def containsDuplicate(self, nums: List[int]) -> bool:
duplicates={}
for i in range(len(nums)):
if i in duplicates:
return False
return True
It passes 11/18 cases, but for the test case of [0], it returns True when the expected output is False. I can't seem to understand why it returns False.
I got it. Return statement was in too deep and I had to update it for every loop.
def containsDuplicate(self, nums: List[int]) -> bool:
duplicates={}
for i in nums:
if i in duplicates:
return True
else:
duplicates[i] = 0
return False ```

Categories