When should I use the [:] to append the result? - python

I have two code examples, both of which work the same:
class Solution(object):
def permute(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
m = len(nums)
ans = []
def solve(lst, tmp):
if len(tmp) == m:
ans.append(tmp)
for i in range(len(lst)):
solve(lst[:i]+lst[i+1:], tmp + [lst[i]])
solve(nums, [])
return ans
and this one:
class Solution(object):
def permute(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
ans = []
l = len(nums)
def solve(tmp, c):
""" why should I use tmp[:] here? instead of tmp?"""
if len(tmp) == l:
ans.append(tmp[:])
for i in c:
if c[i] > 0:
tmp.append(i)
c[i] -= 1
solve(tmp, c)
c[i] += 1
tmp.pop()
solve([], Counter(nums))
return ans
For the line I highlight, if I change it from tmp[:] to tmp, then it will be a list of empty list?
I want to know when should I append a copy of list, and when should I just append the tmpo list?

When you do tmp.append(i), you're implicitly modifying the reference of that list that would be stored inside of ans. When you do a copy, that wouldn't happen
For the first answer, the addition is returning a new list, not appending directly to tmp
To get a similar behavior, you'd have to do
tmp += [lst[i]]
solve(lst[:i]+lst[i+1:], tmp)

Related

How do I turn this recursive solution to a DP solution?

Hi I have drafted a recursive solution for the partition equal subset problem (https://leetcode.com/problems/partition-equal-subset-sum/) on LeetCode which is accepted:
class Solution(object):
def canPartition(self, nums):
"""
:type nums: List[int]
:rtype: bool
"""
if not nums or len(nums) < 2:
return False
if sum(nums) % 2 != 0:
return False
target = sum(nums) // 2
# if the maximum number in nums goes larger than target,
# then this maximum number cannot be partitioned into any subarray
# hence there's no solution in this case, return False early
if max(nums) > target:
return False
nums.sort(reverse = True)
return self.helper(nums, 0, target, 0)
def helper(self, nums, index, target, curr):
# since "target" value is derived from dividing total sum,
# we only need to search for one sum that makes target value in the array
# the rest is guaranteed to sum up to "target"
if curr == target:
return True
for i in range(index, len(nums)):
if curr + nums[i] > target:
continue
if self.helper(nums, i + 1, target, curr + nums[i]):
return True
return False
However, as a follow up, what would be the best way to actually return the two subsets instead of just True/False. What would the code look like with the saved subsets, if I had to update the above existing code? I am one of those people who are starting out with DP. Thanks in advance.
Figured out the solution:
class Solution(object):
def canPartition(self, nums):
"""
:type nums: List[int]
:rtype: bool
"""
if not nums or len(nums) < 2:
return []
if sum(nums) % 2 != 0:
return []
target = sum(nums) // 2
if max(nums) > target:
return []
nums.sort(reverse = True)
res = []
self.helper(nums, 0, target, [], res)
return res
def helper(self, nums, index, target, curr, res):
if sum(curr) == target:
res.append(list(curr))
return
for i in range(index, len(nums)):
if sum(curr) + nums[i] > target:
continue
self.helper(nums, i + 1, target, curr + [nums[i]], res)

not able to solve edge case in number of contiguous subarrays with sum k

I have been trying to solve the "Subarray Sum Equals K" problem on leetcode. However I am not able to solve some test cases with the following code:
from collections import defaultdict
class Solution(object):
def subarraySum(self, nums, k):
"""
:type nums: List[int]
:type k: int
:rtype: int
"""
sumTable = defaultdict(lambda : 0)
count = 0
totalSum = 0
for i in range(0,len(nums)):
totalSum += nums[i]
if(totalSum==k):
count += 1
sumTable[totalSum] += 1
for key in sumTable:
# print(key)
if (key-k) in sumTable:
count += sumTable[key-k]
return count
Found this solution on Github
import collections
class Solution(object):
def subarraySum(self, nums, k):
"""
:type nums: List[int]
:type k: int
:rtype: int
"""
result = 0
accumulated_sum = 0
lookup = collections.defaultdict(int)
lookup[0] += 1
for num in nums:
accumulated_sum += num
result += lookup[accumulated_sum - k]
lookup[accumulated_sum] += 1
return result
Adding on why your solution won't work, is because your TotalSum never resets. Therefore you detect either 0 or 1 solutions.

Unable to move 0's to the end of list properly Python

So the goal here is to move all 0's to the end of the array but I stumble across a problem from these small lines of code.
When I use the input I get the desired output like so:
Input: [0,1,0,3,12]
Output: [1,3,12,0,0]
However, whenever I use this input:
[0,0,1]
I get this output:
[0,1,0]
When I want the output:
[1,0,0]
I have no idea why I thought I implemented this properly:
class Solution:
def moveZeroes(self, nums):
"""
:type nums: List[int]
:rtype: void Do not return anything, modify nums in-place instead.
"""
for counter in range(len(nums)):
if nums[counter] == 0:
nums.pop(counter) #Remove the 0
nums.append(0) #Add to end.
counter-=1 #Check same index just incase adjacent 0
Any input is appreciated. Thanks!
I wouldn't even bother with a manual for loop...
def move_zeroes(nums):
nums[:] = [n for n in nums if n != 0] + [0] * nums.count(0)
x = [0,1,0,3,12]
move_zeroes(x)
print(x)
outputs
[1, 3, 12, 0, 0]
A for loop is not a equivalent to a while loop with increment. Your last line counter-=1 doesn't achieve anything: after you decrement counter, it immediately takes the next value in the range. (To be clear, if you were at iteration counter = 2 for example, no matter what value you leave counter at at the end of this iteration, it will be reassigned to 3 at the next iteration.)
This line:
counter-=1 #Check same index just incase adjacent 0
Does not decrease the indexing for the following indices.
Try this instead:
class Solution:
def moveZeroes(self, nums):
"""
:type nums: List[int]
:rtype: void Do not return anything, modify nums in-place instead.
"""
zeros_found = 0
for counter in range(len(nums)):
idx = counter - zeros_found
if nums[idx] == 0:
nums.pop(idx) #Remove the 0
nums.append(0) #Add to end.
zeros_found += 1 #Account for offset
You could also do this more functionally:
from itertools import filterfalse
# ...
def moveZeroes(self, nums):
none_zeroes = list(filter(None, nums))
zeros = list(filterfalse(None, nums))
return none_zeros + zeros
Or if you don't want to create lists for no reason:
from itertools import filterfalse, chain
# ...
def moveZeroes(self, nums):
none_zeroes = filter(None, nums)
zeros = filterfalse(None, nums)
return list(chain(none_zeros, zeros))
These rely on two implicit facts:
bool(0) is False, and bool(x) when x != 0 is True
filter(None, list) filters list by item's bool value, so no 0s (and opposite for filterfalse)

Given a sorted array, remove the duplicates in-place such that each element appear only once and return the new length

The full question, and I'm starting to learn python online but having issue with this question marked as easy
Given a sorted array, remove the duplicates in-place such that each
element appear only once and return the new length. Do not allocate
extra space for another array, you must do this by modifying the input
array in-place with O(1) extra memory.
class Solution(object):
def removeDuplicates(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
k=0
for i in range(i+1,len(nums)-1):
j=i+1
for j in range(j+1,len(len(nums))):
if nums[i] == nums[j]:
del nums[j]
len_list = nums
return(len_list, nums)
It is fairly easy, once you realize you have to work from the end of the list, so that your deletions do not change the part of the list you have not yet examined.
a = [1,1,1,3,4,5,5,5,5,7,7,7,9,9]
for i in range(len(a)-1,0,-1):
if a[i] == a[i-1]:
del a[i]
Result is
[1, 3, 4, 5, 7, 9]
First answer from #BoarGules is the best one. But we can do it in forward direction also.
a = [1,1,1,3,4,5,5,5,5,7,7,7,9,9]
i =0
l = len(a)-1
while i < l :
if a[i] == a[i+1]:
del a[i+1]
l -=1
else :
i +=1
print(a)
Result will be :
[1, 3, 4, 5, 7, 9]
Looks like you are solving a LeetCode question:
https://leetcode.com/problems/remove-duplicates-from-sorted-array/
If yes, this should be your answer:
class Solution:
def removeDuplicates(self, nums: List[int]) -> int:
if len(nums) == 1:
return 1
i = 0
for j in range(1, len(nums)):
if (nums[i] != nums[j]):
i += 1
nums[i] = nums[j]
return i + 1
It doesn't matter what you leave beyond the returned length.
below code remove duplicates & sort array in descending order.
class Solution(object):
def thirdMax(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
a_value=sorted(set(nums),reverse=True)
if len(a_value) > 2:
a=a_value[2]
else:
a=a_value[0]
return a

From LeetCode Given an array of integers, return indices of the two numbers such that they add up to a specific target

This is an exercise on LeetCode. I get an except of
UnboundLocalError on line 15.
Why? And how to fix it?
class Solution(object):
def twoSum(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[int]
"""
self.nums = []
self.target = int
for i in range(len(nums)):
for j in range(i + 1, len(nums)):
if nums[i] + nums[j] == target:
a = []
return a[i, j]
I believe this would work:
class Solution:
def twoSum(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[int]
"""
n = len(nums)
for i in range(n):
for j in range(i+1, n):
if nums[i] + nums[j] == target:
return [i,j]
class Solution:
def twoSum(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[int]
"""
n = len(nums)
for i in range(n):
for j in range(i+1, n):
if nums[i] + nums[j] == target:
return [i,j]
may be you try it:
if self.nums[i] + self.nums[j] == target:
# ^^^^^ ^^^^^
Let's examine your code:
First scenario (No combination matches target)
The method returns a value which is not yet defined:
return a[i, j]
But a was never defined!
Second scenario (Combination matches target)
The method returns a value which was initialized:
a = []
But, we never set the value at index [i, j], so this still won't work:
return a[i, j]
Solution
When you find a combination that equals the target, return their indices:
class Solution(object):
def twoSum(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[int]
"""
self.nums = []
self.target = int
for i in range(len(nums)):
for j in range(i + 1, len(nums)):
if nums[i] + nums[j] == target:
return i, j
if __name__ == "__main__":
a = Solution()
print a.twoSum([1,2,3,4,5], 5)
See if this helps... return all possible indices:
def getIndices(tlist, target):
return [(tlist.index(i), tlist.index(j)) for x,i in enumerate(tlist) for j in tlist[x:] if i!=j and i+j==target]
How to call:
getIndices(<your-list>, <your-target>)
Examples:
getIndices([1,2,3,4,5,6,7,8], 10) => [(1, 7), (2, 6), (3, 5)]
getIndices([1,2,3,4,5,6,7,8], 100) => []

Categories