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

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)

Related

Leetcode 413: Arithmetic slices Python

Hi I'm trying to solve Leetcode 413: Arithmetic slices. I'm trying to start with a brute force recursive solution.
def numberOfArithmeticSlices(self, nums: List[int]) -> int:
def slices(nums: List[int], i: int):
if (i < 2):
return 0
if nums[i] - nums[i-1] == nums[i-1] - nums[i-2]:
return 1 + slices(nums, i -1)
else:
return slices(nums, i-1)
if len(nums) < 3:
return 0
return slices(nums, len(nums)-1)
This doesn't work for the test case [1,2,3,4] (it returns 2 instead of 3). In my head I know it doesn't work because when the function is called, 1 + slices([1,2,3], 2) returns 2. How can I fix my code to get the arithmetic slice coming from the entire array [1,2,3,4]?
For solving this problem you have to take two steps.
First you have to find all possible contiguous sub-arrays
You have to check them, if they are arithmetic slices.
An understandable solution which is not memory and time efficient is as below:
def numberOfArithmeticSlices(self, nums: List[int]) -> int:
if len(nums) <= 2:
return 0
sub_arrays = self.contiguous_subarray(nums) # type List[List[int]] all contiguous sub arrays with length 3 or more
count = 0
for subset in sub_arrays:
count = count + self.is_arithmetic_subset(subset)
return count
#staticmethod
def is_arithmetic_subset(subset):
if len(subset) <= 2:
return 0
diff = subset[1] - subset[0]
for i in range(2, len(subset)):
if subset[i] - subset[i - 1] != diff:
return 0
return 1
#staticmethod
def contiguous_subarray(nums):
return [nums[i:i + j] for i in range(0, len(nums)) for j in range(3, len(nums) - i + 1)]
But a solution that is little more harder to grasp but is memory and time efficient is as bellow(You could still replace the recursive call with a loop and I think you would get better results doing so):
def numberOfArithmeticSlices(self, nums: List[int]) -> int:
array_len = len(nums)
if array_len <= 2:
return 0
count = self.numberOfArithmeticSlices(nums[:array_len - 1])
diff = nums[array_len - 1] - nums[array_len - 2]
for i in range(2, array_len):
if nums[array_len - i ] - nums[array_len - i - 1] == diff:
count += 1
else:
break
return count

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

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)

Adding numbers within a range of root values returns incorrect value

I am working through LeetCode and this problem has me stuck. I am given a root node of a binary search tree and I am asked to return the sum of all values between L and R inclusive:
Example:
Input: root = [10,5,15,3,7,null,18], L = 7, R = 15
Output: 32 (10+15+7)
This is my attempt:
class Solution:
def rangeSumBST(self, root: TreeNode, L: int, R: int) -> int:
value = 0
if root.val >= L and root.val <= R:
value += root.val
return value
However, this is what it is returning:
Your input [10,5,15,3,7,null,18] 7 15
Output 10
Expected 32
In Python, instead of if root.val >= L and root.val <= R you can simply use L <= root.val <= R.
Then, there are two more conditions to be defined. This'd pass through:
class Solution:
def rangeSumBST(self, root, L, R):
if not root:
return 0
summation = 0
if root.val > L:
summation += self.rangeSumBST(root.left, L, R)
if root.val < R:
summation += self.rangeSumBST(root.right, L, R)
if L <= root.val <= R:
summation += root.val
return summation
Here is LeetCode's iterative solution using stack:
class Solution(object):
def rangeSumBST(self, root, L, R):
ans = 0
stack = [root]
while stack:
node = stack.pop()
if node:
if L <= node.val <= R:
ans += node.val
if L < node.val:
stack.append(node.left)
if node.val < R:
stack.append(node.right)
return ans
References
For additional details, you can see the Discussion Board. There are plenty of accepted solutions with a variety of languages and explanations, efficient algorithms, as well as asymptotic time/space complexity analysis1, 2 in there.
You're stopping at the root of the tree.
Look at the tree recursively.
Try
class Solution:
def rangeSumBST(self, root: TreeNode, L: int, R: int) -> int:
if root is None or root.val < L or root.val > R:
return 0
return root.val + self.rangeSumBST(root.left, L, R) + self.rangeSumBST(root.right, L, R)

Optimize solution runtime to 3Sum problem

I am trying to find all unique triplets within a given set of integers that sum to zero. I have the following code which to me works logically but I keep getting a timeout error. Any advice on what I am missing or how to optimize? I have gone over it several times and I can't see how to make it any faster. Thanks in advance!
class Solution:
def threeSum(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
nums.sort()
for i in range(len(nums)-2):
if i > 0 and nums[i] == nums[i-1]:
continue
target = 0 - nums[i]
j = i +1
k = len(nums) - 1
tgt_sum = 0
trpls = []
while j < k:
tgt_sum = nums[j] + nums[k]
if tgt_sum == target:
x = []
x.append([i,j,k])
if all(item in trpls for item in x) == True:
trpls_list.append([i,j,k])
elif tgt_sum < target:
j += 1
elif tgt_sum > target:
k -= 1
else:
k -= 1
test = Solution()
given_nums = [-1,0,1,2,-1,-4]
print(test.threeSum(given_nums))

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