楼主: 李浩泉
跳转到指定楼层
上一主题 下一主题
收起左侧

[Leetcode] LC Python 刷题笔记 有志者事竟成

   
🔗
 楼主| 李浩泉 2020-8-2 06:47:40 | 只看该作者
全局:
# 965 Univalued Binary Tree

也是一道非常好的通过简单遍历,不需要算法就能解决的二叉树问题。


  1. '''
  2. A binary tree is univalued if every node in the tree has the same value.

  3. Return true if and only if the given tree is univalued.

  4. Example 1:

  5. Input: [1,1,1,1,1,null,1]
  6. Output: true
  7. Example 2:

  8. Input: [2,2,2,5,2]
  9. Output: false

  10. Note:

  11. The number of nodes in the given tree will be in the range [1, 100].
  12. Each node's value will be an integer in the range [0, 99].
  13. '''

  14. def isUnivalTree(self, root: TreeNode) -> bool:
  15.     if not root: return False
  16.     result = []
  17.     current = []
  18.     current.append(root)
  19.         
  20.     while current:
  21.         next_level = []
  22.         for n in current:
  23.             result.append(n.val)
  24.             if n.left:
  25.                 next_level.append(n.left)
  26.             if n.right:
  27.                 next_level.append(n.right)
  28.             current = next_level
  29.     s = set(result)
  30.     return len(s) == 1
复制代码


回复

使用道具 举报

全局:
记得楼主前阵子拿到了facebook DE的面试,能更新一下后来的onsite情况么?十分感谢!
回复

使用道具 举报

🔗
 楼主| 李浩泉 2020-8-4 00:37:56 | 只看该作者
全局:


算法第五计:Greedy 贪心算法

It makes optimal choice at each stage with the intent of finding a global optimum.

# 763 Partition Labels

Complexity Analysis

Time Complexity:O(N), where N is the length of S.

Space Complexity:O(1) to keep data structure last of not more than 26 characters.


  1. '''
  2. A string S of lowercase English letters is given. We want to partition this string into as many parts as possible so that each letter appears in at most one part, and return a list of integers representing the size of these parts.



  3. Example 1:

  4. Input: S = "ababcbacadefegdehijhklij"
  5. Output: [9,7,8]
  6. Explanation:
  7. The partition is "ababcbaca", "defegde", "hijhklij".
  8. This is a partition so that each letter appears in at most one part.
  9. A partition like "ababcbacadefegde", "hijhklij" is incorrect, because it splits S into less parts.
  10. '''

  11. def partitionLabels(self, S):
  12.     last = {c: i for i, c in enumerate(S)}
  13.     j = anchor = 0
  14.     ans = []
  15.     for i, c in enumerate(S):
  16.         j = max(j, last[c])
  17.         if i == j:
  18.             ans.append(i - anchor + 1)
  19.             anchor = i + 1
  20.     return ans
复制代码


回复

使用道具 举报

🔗
 楼主| 李浩泉 2020-8-4 03:41:31 | 只看该作者
全局:
本帖最后由 李浩泉 于 2020-8-4 03:49 编辑

算法第六计:Divide and Conquer 分治法

It breaks down a problem into more sub-problem until these become simple enough to be solved directly.


# 53 Maximum Subarray

Complexity Analysis

Time complexity : O(NlogN)

Space complexity : O(logN)


  1. '''
  2. Given an integer array nums, find the contiguous subarray (containing at least one number) which has the largest sum and return its sum.

  3. Example:

  4. Input: [-2,1,-3,4,-1,2,1,-5,4],
  5. Output: 6
  6. Explanation: [4,-1,2,1] has the largest sum = 6.
  7. Follow up:

  8. If you have figured out the O(n) solution, try coding another solution using the divide and conquer approach, which is more subtle.
  9. '''

  10.     def maxSubArray(self, nums):
  11.         return self.helper(nums, 0, len(nums) - 1)
  12.    
  13.     def cross_sum(self, nums, left, right, p):
  14.         if left == right:
  15.                 return nums[left]

  16.         left_subsum = float('-inf')
  17.         curr_sum = 0
  18.         for i in range(p, left - 1, -1):
  19.             curr_sum += nums[i]
  20.             left_subsum = max(left_subsum, curr_sum)

  21.         right_subsum = float('-inf')
  22.         curr_sum = 0
  23.         for i in range(p + 1, right + 1):
  24.             curr_sum += nums[i]
  25.             right_subsum = max(right_subsum, curr_sum)

  26.         return left_subsum + right_subsum   
  27.    
  28.     def helper(self, nums, left, right):
  29.         if left == right:
  30.             return nums[left]
  31.         
  32.         p = (left + right) // 2
  33.             
  34.         left_sum = self.helper(nums, left, p)
  35.         right_sum = self.helper(nums, p + 1, right)
  36.         cross_sum = self.cross_sum(nums, left, right, p)
  37.         return max(left_sum, right_sum, cross_sum)
  38.         
复制代码


如果不用分治法,也可以做。感觉coding里面的分治算法很像SQL里面的CTE或者in-line sub query。如果不能一口气写完,那就多分几个CTE出来,只要CTE足够多,最后不论多么复杂的query也能做出来。

  1. def maxSubArray(self, nums: List[int]) -> int:
  2.     n = len(nums)
  3.     current_sum = nums[0]
  4.     max_sum = current_sum
  5.     i = 1
  6.     while i < n :
  7.         current_sum = max(nums, current_sum + nums)
  8.         max_sum = max(max_sum, current_sum)
  9.         i += 1
  10.     return max_sum
复制代码


回复

使用道具 举报

全局:
李浩泉 发表于 2020-07-30 09:19:03
没有频率,也没有顺序,就是平推,从#1 Two Sum开始,一直到最后的#1533        
Find the Index of the Large Integer。一边WFH,一边等待着机会
哈哈哈sql不算编程。过于真实
回复

使用道具 举报

🔗
 楼主| 李浩泉 2020-8-4 05:05:25 | 只看该作者
全局:


算法第七计:Dynamic Programming 动态规划



动态规划算法通常用于求解具有某种最优性质的问题。在这类问题中,可能会有许多可行解。每一个解都对应于一个值,我们希望找到具有最优值的解。 动态规划算法与分治法类似,其基本思想也是将待求解问题分解成若干个子问题,先求解子问题,然后从这些子问题的解得到原问题的解。 与分治法不同的是,适合于用动态规划求解的问题,经分解得到子问题往往不是互相独立的。 若用分治法来解这类问题,则分解得到的子问题数目太多,有些子问题被重复计算了很多次。


计算机归根结底只会做一件事:穷举。所有的算法都是在让计算机【如何聪明地穷举】而已,动态规划也是如此。


LC算题基本算法思想总结:

1. 穷举(Proof by exhaustion)

    1.1 算法第一计:Brute Force 暴力搜索
    1.2 算法第二计:Two Pointers 双指针(left / right;fast / slow)
    1.3 算法第三计:Iteration 迭代
    1.4 算法第四计:Recursion 递归

2. 贪婪
    2.1 算法第五计:Greedy 贪心算法

3. 分治
    3.1 算法第六计:Divide and Conquer 分治法

4. 动态规划
    4.1 算法第七计:Dynamic Programming 动态规划

5. 回溯
    5.1 算法第八计:Backtracking 回溯算法

6. 其它未分类
    6.1 算法第九计:Hash Table 哈希表
    6.2 算法第十计:Math 代数法
    6.3 算法第十一计:Union-Find 并查集
    6.4 算法第十二计:Sliding Window 滑动窗口





回复

使用道具 举报

🔗
 楼主| 李浩泉 2020-8-4 05:42:50 | 只看该作者
全局:

算法第七计:Dynamic Programming 动态规划

# 139 Word Break

  1. '''
  2. Given a non-empty string s and a dictionary wordDict containing a list of non-empty words, determine if s can be segmented into a space-separated sequence of one or more dictionary words.

  3. Note:

  4. The same word in the dictionary may be reused multiple times in the segmentation.
  5. You may assume the dictionary does not contain duplicate words.
  6. Example 1:

  7. Input: s = "leetcode", wordDict = ["leet", "code"]
  8. Output: true
  9. Explanation: Return true because "leetcode" can be segmented as "leet code".
  10. Example 2:

  11. Input: s = "applepenapple", wordDict = ["apple", "pen"]
  12. Output: true
  13. Explanation: Return true because "applepenapple" can be segmented as "apple pen apple".
  14.              Note that you are allowed to reuse a dictionary word.
  15. Example 3:

  16. Input: s = "catsandog", wordDict = ["cats", "dog", "sand", "and", "cat"]
  17. Output: false
  18. '''

  19. def wordBreak(self, s: str, wordDict: List[str]) -> bool:
  20.     dp = [False]*len(s)+[True]
  21.     for i in range(len(s)-1, -1, -1):
  22.         dp[i] = any(len(s)-i >= len(word) and word == s[i:i+len(word)] and dp[i+len(word)] for word in wordDict)
  23.     return dp[0]
复制代码
[/i]


  1. def wordBreak(self, s, wordDict):
  2.     if not wordDict:
  3.         return False
  4.     d = [False] * len(s)
  5.     for i in range(len(s)):
  6.         for w in wordDict:
  7.             if w == s[i-len(w)+1:i+1] and (d[i-len(w)] or i-len(w) is -1):
  8.                 d[i] = True
  9.     return d[-1]
复制代码



回复

使用道具 举报

🔗
 楼主| 李浩泉 2020-8-5 06:45:04 | 只看该作者
全局:
本帖最后由 李浩泉 于 2020-8-5 06:53 编辑

做几道DE的真题,检验一下。SDE们也可以过来看看,试试。

# What Is Wrong With This Family?


Michael always knew that there was something wrong with his family. Many strangers were introduced to him as part of it.

Michael should figure this out. He's spent almost a month parsing the family archives. He has all father-son connections of his entire family collected in one place.

With all that data Michael can easily understand who the strangers are. Or maybe the only stranger in this family is Michael? Let's see.

You have a list of family ties between father and son. Each element on this list has two elements. The first is the father's name, the second is the son's name. All names in the family are unique. Check if the family tree is correct. There are no strangers in the family tree. All connections in the family are natural.

Input: list of lists. Each element has two strings. The list has at least one element

Output: bool. Is the family tree correct.



  1. def is_family(tree):
  2.    
  3.     # 先大概清理一下数据,简单条件排除明显错误:排除多个祖先
  4.     father = []
  5.     son = []
  6.     for c in tree:
  7.         father.append(c[0])
  8.         son.append(c[1])
  9.     if len(set(father).difference(set(son))) != 1:
  10.         return False
  11.    
  12.     # 排除互为父子现象
  13.     for j in range(len(tree)):
  14.         for k in range(1,len(tree)):
  15.             if tree[j] == tree[k][::-1]:
  16.                 return False
  17.    
  18.     # 为了构造有序的新树,先做一个小函数,返回当前的Father
  19.     def top_helper(tree):
  20.         father = []
  21.         son = []
  22.         for c in tree:
  23.             father.append(c[0])
  24.             son.append(c[1])
  25.         if len(set(father).difference(set(son))) == 1:
  26.             return ''.join(set(father).difference(set(son)))
  27.    
  28.     # 构建一个有序的新树,保证先祖永远在前,子孙永远在后
  29.     dummy_tree = tree
  30.     list1 = []
  31.     list2 = []
  32.     while len(dummy_tree) > 1:
  33.         top = top_helper(dummy_tree)
  34.         list2 = []
  35.         for i in range(len(dummy_tree)):
  36.             if top in dummy_tree[i]:               
  37.                 list1.append(dummy_tree[i])
  38.             else:
  39.                 list2.append(dummy_tree[i])
  40.         dummy_tree = list2
  41.     new_tree = list1 + list2
  42.    
  43.     # 字典法,祖先为0,后世子孙从1开始递加,如果最后字典成立,则返回True
  44.     if len(new_tree) < 2: return True
  45.     dic = {}
  46.     dic[new_tree[0][0]] = 0
  47.     dic[new_tree[0][1]] = 1
  48.     num = 1
  49.     for i in range(1,len(new_tree)):   
  50.         if new_tree[i][0] not in dic or new_tree[i][1] in dic:
  51.             return False
  52.         elif new_tree[i][1] not in dic:
  53.             dic[new_tree[i][1]] = num + 1
  54.             num += 1
  55.     return True

  56. if __name__ == "__main__":
  57.     #These "asserts" using only for self-checking and not necessary for auto-testing
  58.     assert is_family([
  59.       ['Logan', 'Mike']
  60.     ]) == True, 'One father, one son'
  61.     assert is_family([
  62.       ['Logan', 'Mike'],
  63.       ['Logan', 'Jack']
  64.     ]) == True, 'Two sons'
  65.     assert is_family([
  66.       ['Logan', 'Mike'],
  67.       ['Logan', 'Jack'],
  68.       ['Mike', 'Alexander']
  69.     ]) == True, 'Grandfather'
  70.     assert is_family([
  71.       ['Logan', 'Mike'],
  72.       ['Logan', 'Jack'],
  73.       ['Mike', 'Logan']
  74.     ]) == False, 'Can you be a father to your father?'
  75.     assert is_family([
  76.       ['Logan', 'Mike'],
  77.       ['Logan', 'Jack'],
  78.       ['Mike', 'Jack']
  79.     ]) == False, 'Can you be a father to your brother?'
  80.     assert is_family([
  81.         ["Logan","Mike"],
  82.         ["Alexander","Jack"],
  83.         ["Jack","Alexander"]
  84.     ]) == False
  85.     assert is_family([
  86.         ["Logan","Mike"],
  87.         ["Alexander","Jack"],
  88.         ["Jack","Logan"]
  89.     ]) == True,'Family connections can be listed in any directions'
  90.     assert is_family([
  91.         ['Logan', 'Mike'],
  92.         ['Logan', 'Jack'],
  93.         ['Mike', 'Alexander']
  94.     ]) == True
  95.     assert is_family([
  96.       ['Logan', 'William'],
  97.       ['Logan', 'Jack'],
  98.       ['Mike', 'Alexander']
  99.     ]) == False, 'Looks like Mike is stranger in Logan\'s family'
  100.     print("Looks like you know everything. It is time for 'Check'!")
复制代码


[/i][/i][/i][/i][/i][/i][/i]

回复

使用道具 举报

🔗
 楼主| 李浩泉 2020-8-5 07:03:38 | 只看该作者
全局:
本帖最后由 李浩泉 于 2020-8-5 07:57 编辑

上面这道题最大的难点在于:Family connections can be listed in any directions。一开始不知道谁是先祖,谁是子孙,逻辑判断的时候无从下手,无法保证IF条件可以覆盖所有场景。所以

1. 首先试图创建新的Tree,祖先在前,子孙在后;
2. 为了这个新Tree,还需要构建一个小函数,判断当前的祖先;
3. 为了创建新的Tree,还需要提前清理现有的数据,排除一些明显错误,比如:多个祖先,互为父子
4. 排除了,多个祖先F,互为父子等情况,也建立了有序的新Tree,这个时候就可以用字典,从头开始遍历,祖先为0,后面的依次加1,如果字典成立,则True,否则就是False。

DE的考题,非常实际,需要用Python在处理Data Pipeline ETL上做数据清理和逻辑判断。

后来看了某5级SDE的代码,心里又崩溃了,看了好久才理解:

SDE的高级字典法:from collections import defaultdict


当我使用普通的字典时,用法一般是dict={},添加元素的只需要dict[element] =value即,调用的时候也是如此,dict[element] = xxx,但前提是element字典里,如果不在字典里就会报错。defaultdict的作用是在于,当字典里的key不存在但被查找时,返回的不是keyError而是一个默认值。
  1. dict1 = defaultdict(int)
  2. dict2 = defaultdict(set)
  3. dict3 = defaultdict(str)
  4. dict4 = defaultdict(list)
  5. dict1[2] ='two'

  6. print(dict1[1])
  7. print(dict2[1])
  8. print(dict3[1])
  9. print(dict4[1])



  10. 0
  11. set()

  12. []
复制代码




  1. from collections import defaultdict

  2. def is_family(tree):
  3.     anscestor = defaultdict(set)
  4.     for father, son in tree:
  5.         if father == son: return False
  6.         if father in anscestor[son]: return False
  7.         if son in anscestor[father]: return False
  8.         if anscestor[father] & anscestor[son]: return False
  9.         anscestor[son] |= {father} | anscestor[father]
  10.     adam = [person for person in anscestor if not anscestor[person]]
  11.     return len(adam) == 1
复制代码






回复

使用道具 举报

全局:
可以的,加油

评分

参与人数 1大米 +1 收起 理由
李浩泉 + 1 感谢脸书DE的支持!!!

查看全部评分

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册账号
隐私提醒:
  • ☑ 禁止发布广告,拉群,贴个人联系方式:找人请去🔗同学同事飞友,拉群请去🔗拉群结伴,广告请去🔗跳蚤市场,和 🔗租房广告|找室友
  • ☑ 论坛内容在发帖 30 分钟内可以编辑,过后则不能删帖。为防止被骚扰甚至人肉,不要公开留微信等联系方式,如有需求请以论坛私信方式发送。
  • ☑ 干货版块可免费使用 🔗超级匿名:面经(美国面经、中国面经、数科面经、PM面经),抖包袱(美国、中国)和录取汇报、定位选校版
  • ☑ 查阅全站 🔗各种匿名方法

本版积分规则

>
快速回复 返回顶部 返回列表