Skip to content

Day 4. 02/11/20 #88

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
4 tasks done
tech-cow opened this issue Feb 11, 2020 · 5 comments
Closed
4 tasks done

Day 4. 02/11/20 #88

tech-cow opened this issue Feb 11, 2020 · 5 comments

Comments

@tech-cow
Copy link
Owner

tech-cow commented Feb 11, 2020

Leetcode

  • 160 Intersection of Two Linked Lists (x2 Apperence)
  • 116 | Populating Next Right Pointers in Each Node
  • 543 Diameter of Binary Tree
  • 560 | Subarray Sum Equals K (Can you solve it in O(1) Space?)
@tech-cow
Copy link
Owner Author

160 Intersection of Two Linked Lists (x2 Apperence)

'''
[8:23] Start


Thoughts:
    [8:23] Sol 1 (Hashtable):
        looping A and B seperately and store hashtable of 
            {
                node reference : index of passing 
            }

        Looping again on shorter linked list and find first intersection

        Time: O(len(A)) + O(len(B))
        Space: O(len(A)) + O(len(B)) -> Hashmap
    
    
    
    [8:26] is O1 space possible?
    
    
    
    
    [8:30] Sol 2 (Two Pointers):
        Using slow fast pointer to reverse the  pointer.
        
        A -> all the way to c, increment each tiem by 1 
        B -> all the way to c, increment each tiem by 1
        
        if either A or B hits the end of c, rotate to other track
        A -> B track or B -> A track
        Because the velocity of each node are different, eventually they would cross each other
            
        Time: O(len(A)) + O(len(B))
        Space: O(1)

'''

# [8:35] Start Coding
# [8:47] Bug-free
class Solution(object):
    def getIntersectionNode(self, head1, head2):
        cur1, cur2 = head1, head2
        lastNode1, lastNode2 = None, None
        while cur1:
            if cur1.next == None:
                lastNode1 = cur1
            cur1 = cur1.next   
                
        while cur2:
            if cur2.next == None:
                lastNode2 = cur2
            cur2 = cur2.next
            
        if lastNode1 != lastNode2:
            return None
        
        
        cur1, cur2 = head1, head2
        while cur1 != cur2:
            if cur1 and cur1.next == None:
                cur1 = head2
                if cur2 and cur2.next == None:
                    cur2 = head1
                else:
                    cur2 = cur2.next
                
            elif cur2 and cur2.next == None:
                cur2 = head1
                if cur1 and cur1.next == None:
                    cur1 = head2
                else:
                    cur1 = cur1.next
            else:
                cur1 = cur1.next
                cur2 = cur2.next
        
        return cur1

@tech-cow
Copy link
Owner Author

116 | Populating Next Right Pointers in Each Node

This is cancer, looking @ Solution now

"""
# Definition for a Node.
class Node(object):
    def __init__(self, val=0, left=None, right=None, next=None):
        self.val = val
        self.left = left
        self.right = right
        self.next = next
        
[8:51] Start
[9:43] Lots of bug, bad implementation, but got it to work with O(Height) Space
You kind of need left and right children to be able to process the 

"""
class Solution(object):
    def connect(self, root):
        if not root: return None
        height = self.getHeight(root)
        newRoot = Node(root.val)
        self.makeBinaryTree(root, newRoot)
        lastUnlinkedNode = [None] * (height * 20)
        level = 0
        self.connectHorizontalNode(newRoot, lastUnlinkedNode, level)
        return newRoot
    
    def getHeight(self, root):
        height = 0
        if root and root.left:
            height += 1
            root = root.left
        return height + 1
    
    def makeBinaryTree(self, root, newRoot):
        if not root: return 
        if root.left:
            newRoot.left = Node(root.left.val)
        if root.right:
            newRoot.right = Node(root.right.val)

        left = self.makeBinaryTree(root.left, newRoot.left)
        right = self.makeBinaryTree(root.right, newRoot.right)
    
    def connectHorizontalNode(self, newRoot, lastUnlinkedNode, level):
        if not newRoot: return
        level += 1
        left = self.connectHorizontalNode(newRoot.left, lastUnlinkedNode, level)
        right = self.connectHorizontalNode(newRoot.right, lastUnlinkedNode, level)
        
        if left and right:
            if lastUnlinkedNode[level]:
                lastUnlinkedNode[level].next = left
            left.next = right
            lastUnlinkedNode[level] = right
        return newRoot

@tech-cow
Copy link
Owner Author

116 | Populating Next Right Pointers in Each Node

BFS Solution

class Solution(object):
    def connect(self, root):
        if not root:
            return 
        queue = [root]
        while queue:
            curr = queue.pop(0)
            if curr.left and curr.right:
                curr.left.next = curr.right
                if curr.next:
                    curr.right.next = curr.next.left
                queue.append(curr.left)
                queue.append(curr.right)

image


image

@tech-cow
Copy link
Owner Author

543. Diameter of Binary Tree

bug-free

class Solution(object):
    def diameterOfBinaryTree(self, root):
        if not root: return 0
        globalMax = [-float('inf')]
        self.dfsHelper(root, globalMax)
        return globalMax[0]

    
    def dfsHelper(self, root, globalMax):
        if not root: return 0
        
        left = self.dfsHelper(root.left, globalMax)
        right = self.dfsHelper(root.right, globalMax)    
        curMax = left + right
        globalMax[0] = max(curMax , globalMax[0])
        return max(left, right) + 1

@tech-cow
Copy link
Owner Author

tech-cow commented Feb 12, 2020

560. Subarray Sum Equals K

直接看答案,没有除暴力解法以外更好的思路,引用下面文章

作者:charon____
链接:https://leetcode-cn.com/problems/subarray-sum-equals-k/solution/c-nshi-jian-nkong-jian-xiang-jie-by-charon____/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

首先对于这类题,暴力的做法是嵌套循环,以每个元素为起始点遍历扫描,检查子数组和是否满足情况。时间复杂度为 O(n^2),空间复杂度为O(1)。

进一步的优化思路:

首先:优化什么?

目前时间复杂度高,空间复杂度是常数,所以优化点在时间上
时间复杂度的优化都是通过空间来换取时间,而占用存储空间的数据结构应该满足常数时间查找
然后:怎么优化?

暴力算法中有没有重复运算?简单来看,有很多重复的加法运算。例如,在下标为0的时候,运算过 nums[0] + nums[1] + nums[2],在下标为1的时候,又算了一次nums[1] + nums[2]
找到重复运算后怎么消除重复运算?上例中,重复计算了nums[1] + nums[2],换一种思路,实际上不需要加法,只需要 nums[0] + nums[1] + nums[2] - nums[0],再写的清晰一些,用sum[i]表示从0到i所有元素的和,那么nums[1] + nums[2] = sum[2] - sum[0]。这里的sum[i]实际上就是一种前缀和的思路,只需要遍历一次就可以知道所有的前缀和,存在map里,用的时候就可以实现在常数时间的查找。
有了大体的方向后,具体的map怎么存,key是什么,value是什么?对于这个问题来说,我们需要找到的是target k,即sum[j] - sum[i] = k (j > i),k已知,sum[j]在迭代过程中逐步计算。需要存储的就只有sum[i],查找sum[i]要常数时间,那么map的key应该是sum[i]。根据约束条件,value应该是当前值的下标。但是在实际实现的时候可以把这个约束隐藏在循环中,对于当前问题,要找到满足子数组的个数,value可以用来存储到当前位置,前缀和的个数,那么在找到满足的sum[i] = sum[j] - k的时候,最后的结果只需要加上map[sum[j] - k]即可。


class Solution:
    def subarraySum(self, nums, target):
        '''
        dic structure
        {
            preSum at ith element for i in range(len(nums)) : apperence count
        }
        '''
        
        dic = {0:1}  # Sum of 0 already exist to be 1.
        res = preSum = 0
        for num in nums:
            preSum += num
            # Similar to 2Sum here
            if (preSum - target) in dic:
                res += dic[preSum - target]
            dic[preSum] = dic.get(preSum, 0) + 1
        return res

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant