tech-cow/leetcode

Day 2. 02/09/20

tech-cow opened this issue · 7 comments

  • 257 | Binary Tree Paths (Recurisive + Iterative)
  • 34 Find First and Last Position of Element in Sorted Array
  • 67 Add Binary
  • 297 | Serialize and Deserialize Binary Tree
  • 273. Integer to English Words
  • 76 Minimum Window Substring

257 | Binary Tree Paths (Recurisive + Iterative)

[7:57] - [8:02] Brainstorming

image

[8:02] Solution 1: Recursive DFS

Bug 1

[8:09] Bug 1: 
    line: self.dfsHelper(root.left, tempPath + root.val + "->", res)
    bug: cannot concatenate "str" and "int" objects

[8:10] Recursive DFS Bug Free

class Solution(object):    
    def binaryTreePaths(self, root):
        if not root: return ""
        res = []
        self.dfsHelper(root, "", res)
        return res

    def dfsHelper(self, root, tempPath, res):
        if not root: return
        
        if not root.left and not root.right:
            res.append(tempPath + str(root.val))
            return
    
        if root.left:
            self.dfsHelper(root.left, tempPath + str(root.val) + "->", res)
        
        if root.right:
            self.dfsHelper(root.right, tempPath + str(root.val) + "->", res)

[8:11] Solution 2 : Iterative BFS

[8:20] Bug 1

    Line:  queue = deque([(root, str(root.val) + "->")])
    bug : 
        getting ["1->1->3","1->1->2->5"] as output
        shouldn't need to initialize from scractch, just "" since root itself
        will be added later

[8:22] BFS Bugfree

from collections import deque
class Solution(object):
    def binaryTreePaths(self, root):
        if not root: return ""
        queue = deque([(root, "")])
        res = []
        
        while queue:
            node, curPath = queue.popleft()
            if not node.left and not node.right:
                res.append(curPath + str(node.val))
            if node.left:
                queue.append((node.left, curPath + str(node.val) + "->"))
            if node.right:
                queue.append((node.right, curPath + str(node.val) + "->"))
        return res

[8:23] Solution 3 : Stack Bugfree

class Solution(object):
    def binaryTreePaths(self, root):
        if not root: return ""
        stack = [(root, "")]
        res = []
        
        while stack:
            node, curPath = stack.pop()
            if not node.left and not node.right:
                res.append(curPath + str(node.val))
            if node.left:
                stack.append((node.left, curPath + str(node.val) + "->"))
            if node.right:
                stack.append((node.right, curPath + str(node.val) + "->"))
        return res

Aftermath

Duration: [8:25 Finish] Total 28 mins

Bug retrospect:

  1. check type when adding elements.
  2. thinking twice about queue/stack initialization.

34 Find First and Last Position of Element in Sorted Array

Bug-free

"""
[Start] | 11:47
"""
class Solution(object):
    def searchRange(self, nums, target):
        if not nums: return [-1, -1]
        leftIndex = self.findLeftIndex(nums, target)
        rightIndex = self.findRightIndex(nums, target)
        return [leftIndex , rightIndex]
    
    
    def findLeftIndex(self, nums, target):
        left, right = 0, len(nums) - 1
        while left + 1 < right:
            mid = (left + right) // 2
            if nums[mid] == target:
                right = mid
            elif nums[mid] < target:
                left = mid
            else:
                right = mid
        # Post
        if nums[left] == target:
            return left
        if nums[right] == target:
            return right
        return -1

        
    def findRightIndex(self, nums, target):
        left, right = 0, len(nums) - 1
        while left + 1 < right:
            mid = (left + right) // 2
            if nums[mid] == target:
                left = mid
            elif nums[mid] < target:
                left = mid
            else:
                right = mid
        # Post
        if nums[right] == target:
            return right
        if nums[left] == target:
            return left
        return -1

67 Add Binary

class Solution(object):
    def addBinary(self, a, b):
        a, b = a[::-1], b[::-1]
        m, n = len(a), len(b)
        diff = max(m, n) - min(m, n)
        
        for i in range(diff):
            if m < n : 
                a += "0"
            else:
                b += "0"
        
        carry = 0
        res = ""
        for i in range(max(m, n)):
            curSum = int(a[i]) + int(b[i]) + carry
            carry = 0
            if curSum == 3:
                carry += 1
                res += "1"
            elif curSum >= 2:
                carry += 1
                res += "0"
            else:
                carry = 0
                res += str(curSum)
        if carry:
            res += str(carry) 
        return res[::-1]

看答案以后更近

class Solution(object):
    def addBinary(self, a, b):
        i , j  = len(a) - 1, len(b) - 1
        carry = 0
        res = ""
        
        while i >= 0 or j >= 0 or carry:
            if i >= 0:
                carry += int(a[i])
                i -= 1
            if j >= 0:
                carry += int(b[j])
                j -= 1
            res = str(carry % 2) + res
            carry //= 2
        return res
            

记得找找有没有Follow up

297 | Serialize and Deserialize Binary Tree

Struggle a bit, but figure out later, a bit rusty |

Need to code again + try DFS

from collections import deque
class Codec:
    def serialize(self, root):
        if not root: return ""
        res = []
        queue = deque([root])
        while queue:
            node = queue.popleft()
            if node:
                res.append(str(node.val))
                queue.append(node.left)
                queue.append(node.right)
            else:
                res.append("x")
        return ",".join(res)
        
        
    def deserialize(self, nums):
        if not nums: return None
        nums = nums.split(",")
        index = 0
        root = TreeNode(nums[index])
        queue = deque([root])
        
        while queue:
            node = queue.popleft()
            index += 1
            if index < len(nums) and nums[index] != "x":
                node.left = TreeNode(nums[index])
                queue.append(node.left)
                
            index += 1
            if index < len(nums) and nums[index] != "x":
                node.right = TreeNode(nums[index])
                queue.append(node.right)
        return root

Try DFS below

class Codec:
    def serialize(self, root):
        def helper(node):
            if not node:
                return ["None"]
            res = [str(node.val)]
            res.extend(helper(node.left))
            res.extend(helper(node.right))
            return res
        return ",".join(helper(root))
    
    
    def deserialize(self, data):
        if not data:
            return None
        def helper(data):
            if not data:
                return None
            cur = data.pop(0)
            if cur == "None":
                return None
            node = TreeNode(cur)
            node.left = helper(data)
            node.right = helper(data)
            return node
        return helper(data.split(","))

273. Integer to English Words

'''
[8:41] Start

Thoughts (Didn't execute since not sure?):
    Use a stack, and looking @ elements from the end
    Having a hashmap
        {
            key                      |       val
            reverse index of input   |    assoicated english words (ex: "hundred", "thousand")
        }
    manually input some logic around index
    
    
        
[8:44] a bit cancer, give up | Solution Checking & retrospect

[8:44 - 10:52] Eat, Shower, think about this shit, and having brain fart but finally crack it

[10:53] Start Coding again

Problem Soving:
    1. digits rules : name changes every thousands
        1,000,000,000
        b   m   t

    2. Using divide and conquer to continue breaking large number to smaller instance
        and have a few base case to handle any numbers smaller than hundreds
      
[11:41] FUCK it, so many edge case... why?
'''

# dfs: make sure to keep track of parameter passing 
class Solution(object):
    def numberToWords(self, num):
        less_than_20 = ["", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten", "Eleven", "Twelve", "Thirteen", "Fourteen", "Fifteen", "Sixteen", "Seventeen", "Eighteen", "Nineteen", "Twenty"]
        tens = ["", "Ten", "Twenty", "Thirty", "Forty", "Fifty", "Sixty", "Seventy", "Eighty", "Ninety"]
        thousands = ["" , "Thousand", "Million", "Billion"]

        res = ""
        if num == 0: return "Zero"
        for i in range(len(thousands)):
            if num % 1000 != 0:
                res = self.dfsHelper(num % 1000, less_than_20, tens).strip() + " " +  thousands[i] + " " + res
            num //= 1000
        return res.strip()

    def dfsHelper(self, num, less_than_20, tens):
        if num < 20:
           return less_than_20[num] 
        elif 20 <= num < 100:
            return tens[num // 10] + " " + less_than_20[num % 10]
        elif 100 <= num <= 999:
            return less_than_20[num // 100] + " Hundred " + self.dfsHelper(num % 100, less_than_20, tens)

76 Minimum Window Substring

'''
start[6:12]

Problem Solving:
    [?] Sliding window algorithm
        * Potentially scan through with 2 pointers
            - left being the window shrinker
            - right being the window extender
            
            extend right point until meeting the condition of S contains all T
                take GlobalMin
                then shrink the size of left
        
        2 pointer algorithm takes O(N), not sure yet for checking S contains all T part, I am a bit stuck here.
        Stuck:
            One way to verify Target in S, is the making a set of every window
                but that takes O(len(window)) time complexity for convertion
                    
                    Can we make a dictionary of S before hand
                    
                    "ADOBECODEBANC"
                    
                    {
                        char  :  count
                        A     :     1    
                    }
                    
                I can think of a way in which having Target becomes a hashset
                Having a fixed hashtable to store S's state initially
                Having a second hashtable to change count frequency
                    If visted, count of associated element decrement by 1
                
                
                Each time, for loop -> Target hashset:
                    then find comparision of inital hashtable & frequently changed hastable to get the diff
                        If diff more than 1 for every element in hashset
                            Meet the condition
                
                Time Complexity: 
                    O(N) + O(size of Target)
                    
        [6:26] Ok, having brainfart , solution time?
        [7:06] Done, need to re-do
'''

from collections import Counter
class Solution:
    def minWindow(self, nums , target):
        if nums is None: return ""
        targetHash = Counter(target)
        curHash = {}
        
        targetCount = len(targetHash)
        matched = 0
        
        globalMin = float("inf")
        size = len(nums)
        res = ""
        
        j = 0
        for i in range(size):
            # 不断增大窗口大小,知道满足所有Match需求
            while j < size and matched < targetCount:
                if nums[j] in targetHash:
                    curHash[nums[j]] = curHash.get(nums[j], 0) + 1
                    if curHash[nums[j]] == targetHash[nums[j]]:
                        matched += 1
                j += 1
                
            # 更新最小值
            if j - i < globalMin and matched == targetCount:
                globalMin = j - i
                res = nums[i:j]

            # 删除left的一个元素,使得窗口继续滑动
            if nums[i] in targetHash:
                if curHash[nums[i]] == targetHash[nums[i]]:
                    matched -= 1
                curHash[nums[i]] -= 1
        return res

Sliding Window Template

"""
[start] 12:34

Problem Solving Thought Process:

1. Brute Force
Using 2 for loops to find out 2 element that sums up to the target
Constantly update the minimum length in a globalMin

globalMin = infi
for i -> n
    for j -> n
        cur_sum += nums[j]
        if cur_sum > target:
            globalMin = min(globalMin, cur_sum)
            break
return globalMin

Time: O(N^2)
Space: O(1)


2. Two Pointer 
We can potentially only iterate "j" from beginning to end once by moving "i" along the way

Time: O(N)
Space: O(1)
"""

#[Coding Start] 12:39
#[Coding Finish] 12:43
#[Eyeballing code] 12:43 - 12:46
# Bug
"""
globalMin = float('inf')
curSum = 0
j = 0

for i in range(len(nums)):
    while j < len(nums) and curSum < target:
        curSum += nums[j]
        j += 1

    if curSum >= target:
        globalMin = min(globalMin, j - i)

    curSum -= nums[i]

return globalMin   ->  bug1. 如果没有找到合适的结果,应该返回0而不是初始值的infinite

fail testcases:

3
[1,1]
"""
        
class Solution(object):
    def minSubArrayLen(self, target, nums):      
        globalMin = float('inf')
        curSum = 0
        j = 0
        
        for i in range(len(nums)):
            while j < len(nums) and curSum < target:
                curSum += nums[j]
                j += 1
            
            if curSum >= target:
                globalMin = min(globalMin, j - i)
            
            curSum -= nums[i]
        
        return globalMin if globalMin != float('inf') else 0