Leetcode Contest 190
Contents
What went well: I solved first three problems relatively quickly and have working intuition on the last problem.
What did not go well:
-
problem 2 is a two pointer problem, I spent time implmenting the
O(N^2)
approach. This can be improlved by reason through the input size and do not settle for a inefficient solution. -
problem 3 is a problem on trees. The algorithm I settled on computing all possible paths shows duplication paths. At the end I have to resolve to an implementation with many branch checks. To improve, I want to find a clean solution to handle such answer from the bottom up senario.
-
problem 4 is a DP problme. I came up with a 3D state representation which is not efficient enough. Missing insight is noticing the third dimension on
k
is not necessary and this problem is essentially longest common subsequence.
Problem 1
This is a straightforward problem.
Problem 2 1456. Maximum Number of Vowels in a Substring of Given Length
# two pointers solution
def maxVowels(self, s: str, k: int) -> int:
vs = 'aeiou'
if not s:
return 0
if len(s) == 1:
if s in vs:
return 1
return 0
cnt_count = 0
j = 0
ans = -math.inf
for i in range(len(s)):
if s[i] in vs:
cnt_count += 1
while j < i and i - j + 1 > k:
if s[j] in vs:
cnt_count -= 1
j += 1
ans = max(ans, cnt_count)
return ans
Problem 3 1457. Pseudo-Palindromic Paths in a Binary Tree
# 1. collect all binary tree paths from top to bottom.
# 2. on the collection, check if each path is valid. count all the valid ones.
def pseudoPalindromicPaths (self, root: TreeNode) -> int:
def is_psudo(path):
hist = {k:0 for k in range(10)}
for n in path:
hist[n] += 1
odd_count = 0
for v in hist.values():
if v % 2 == 1:
odd_count += 1
return odd_count <= 1
def get_paths(root):
if not root:
return []
if not root.left and not root.right:
return [[root.val]]
elif not root.left:
return [ [root.val] + p for p in get_paths(root.right)]
elif not root.right:
return [ [root.val] + p for p in get_paths(root.left)]
else:
left = get_paths(root.left)
right = get_paths(root.right)
paths = []
for path in left + right:
paths.append([root.val] + path)
return paths
count = 0
for path in get_paths(root):
if is_psudo(path):
count += 1
return count
Problem 4 1458. Max Dot Product of Two Subsequences
# TLE Version
class Solution:
def maxDotProduct(self, nums1: List[int], nums2: List[int]) -> int:
n1, n2 = len(nums1), len(nums2)
memo = {}
self.helper(nums1, n1, nums2, n2, min(n1, n2), memo)
return max(memo.values())
# dp[i][j][k]: value of size k dot product from first i of nums1, and first j of nums2
def helper(self, arr1, i, arr2, j, k, memo):
if (i, j, k) in memo:
return memo[(i, j, k)]
if k == 1:
memo[(i, j, 1)] = max(max(arr1[:i]) * max(arr2[:j]), min(arr1[:i]) * min(arr2[:j]))
return memo[(i, j, 1)]
if i == 1:
memo[(1, j, k)] = max([arr1[0] * x for x in arr2[:j]])
return memo[(1, j, k)]
if j == 1:
memo[(i, 1, k)] = max([arr2[0] * x for x in arr1[:i]])
return memo[(i, 1, k)]
ans = max(max(0, self.helper(arr1, i - 1, arr2, j - 1, k - 1, memo)) + arr1[i - 1] * arr2[j - 1], \
self.helper(arr1, i - 1, arr2, j, k, memo), \
self.helper(arr1, i, arr2, j - 1, k, memo))
memo[(i, j, k)] = ans
return ans
# The only trick is to drop a dot product if < 0.
class Solution:
def maxDotProduct(self, nums1: List[int], nums2: List[int]) -> int:
return self.helper(tuple(nums1), len(nums1), tuple(nums2), len(nums2))
@functools.lru_cache(None)
def helper(self, arr1, i, arr2, j):
if i == 0:
return -math.inf
if j == 0:
return -math.inf
return max([max(0, self.helper(arr1, i - 1, arr2, j - 1)) + arr1[i - 1] * arr2[j - 1],\
self.helper(arr1, i - 1, arr2, j),\
self.helper(arr1, i, arr2, j - 1)])
Author Michael
LastMod 2020-05-24