【LeetCode】100~200题



2020年04月10日    Author:Guofei

文章归类: 刷题    文章编号: 595

版权声明:本文作者是郭飞。转载随意,标明原文链接即可。本人邮箱
原文链接:https://www.guofei.site/2020/04/10/lc1.html


100. Same Tree

递归基础题,需要练

class Solution:
    def isSameTree(self, p: TreeNode, q: TreeNode) -> bool:
        if p is None and q is None:
            return True
        if p is None or q is None:
            return False
        if p.val!=q.val:
            return False
        return self.isSameTree(p.left,q.left) and self.isSameTree(p.right,q.right)

101. Symmetric Tree

跟上一个题一模一样

class Solution:
    def isSymmetric(self, root: Optional[TreeNode]) -> bool:
        def is_symm(left,right):
            if left is None and right is None:
                return True
            if left is None or right is None:
                return False
            if left.val!=right.val:
                return False
            return is_symm(left.left,right.right) and is_symm(left.right,right.left)

        if root is None:
            return True
        return is_symm(root.left,root.right)

102. Binary Tree Level Order Traversal

经典的 level order,也就是 BFS

class Solution:
    def levelOrder(self, root: TreeNode) -> List[List[int]]:
        queue,res=[root],[]
        while queue:
            new_queue=[]
            res_tmp=[]
            for node in queue:
                if node is None:
                    continue
                res_tmp.append(node.val)
                new_queue.append(node.left)
                new_queue.append(node.right)
            queue=new_queue
            if res_tmp:
                res.append(res_tmp)
        return res

因为返回值 res[level] 这种格式,因此 DFS 也挺方便

103. Binary Tree Zigzag Level Order Traversal

先 level order ,然后奇数位倒置

class Solution:
    def zigzagLevelOrder(self, root: TreeNode) -> List[List[int]]:
        res=[]
        queue=[root]

        while queue:
            new_queue=[]
            res_tmp=[]
            for node in queue:
                if node is None:
                    continue
                res_tmp.append(node.val)
                new_queue.append(node.left)
                new_queue.append(node.right)

            if res_tmp:
                res.append(res_tmp)
            queue=new_queue


        for i in range(len(res)):
            if i%2==1:
                res[i]=res[i][::-1]

        return res

104. Maximum Depth of Binary Tree

dfs+cache

class Solution:
    def maxDepth(self, root: Optional[TreeNode]) -> int:
        if root is None:
            return 0
        res=[0]

        def dfs(node,num):
            if node is None:
                res[0]=max(res[0],num)
                return

            dfs(node.left,num+1)
            dfs(node.right,num+1)

        dfs(root,0)
        return res[0]

105~106

  • Construct Binary Tree from Preorder and Inorder Traversal
  • Construct Binary Tree from Inorder and Postorder Traversal

感觉要背下来

##

class Solution:
    def levelOrderBottom(self, root: TreeNode) -> List[List[int]]:
        res=[]
        queue=[root]
        while queue:
            new_queue=[]
            res_tmp=[]
            for node in queue:
                if node is None:
                    continue
                res_tmp.append(node.val)
                queue.append(node.left)
                queue.append(node.right)

            queue=new_queue
            if res_tmp:
                res.append(res_tmp)

        return res[::-1]

108.

108.Convert Sorted Array to Binary Search Tree,基本题目了,不用背也会

class Solution:
    def sorted2BST(self, nums):
        if not nums:
            return None
        mid = len(nums) // 2
        return TreeNode(val=nums[mid], left=self.sorted2BST(nums[:mid]), right=self.sorted2BST(nums[mid + 1:]))

109.Convert Sorted List to Binary Search Tree

答案也不贴了,用几个基本元素拼起来就行了

110. Balanced Binary Tree

一开始觉得是这样的:把所有节点的深度列出来,然后最大深度和最小深度相差1即可。但这样过不了测试,反例 [1,2,3,4,5,6,null,8] 被判断为否,测试用例应当为 True。

平衡二叉树的正式定义为:左子树和右子树深度相差不超过1,跟上面的理解有些差距

# 错误解法
class Solution:
    def isBalanced(self, root: TreeNode) -> bool:
        levels=[]
        def dfs(node,level):
            if node is None:
                levels.append(level)
                return

            dfs(node.left,level+1)
            dfs(node.right,level+1)


        dfs(root,0)

        return max(levels)<=min(levels)+1:

正确解法

class Solution:
    def isBalanced(self, root: TreeNode) -> bool:
        res=[True]

        def dfs(node):
            if res[0] is False:
                return
            if node is None:
                return 0

            left_depth=dfs(node.left)
            # None 代表已经全局判断为 False 了,无须再计算level
            if left_depth is None:
                return
            right_depth=dfs(node.right)
            if right_depth is None:
                return
            if abs(left_depth-right_depth)>1:
                res[0]=False
                return
            else:
                return max(left_depth,right_depth)+1

        dfs(root)
        return res[0]

111. Minimum Depth of Binary Tree

这题也是对定义理解问题,是叶子节点的level

dfs

class Solution:
    def minDepth(self, root: TreeNode) -> int:
        if root is None:
            return 0


        res=[100000]

        def dfs(node,level):
            if node is None:
                return
            if node.left is None and node.right is None:
                res[0]=min(res[0],level)
                return
            else:
                dfs(node.left,level+1)
                dfs(node.right,level+1)

        dfs(root,1)
        return res[0]

112. Path Sum

就dfs

class Solution:
    def hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool:
        res=[]
        def dfs(node,path_sum):
            if node is None:
                return
            if node.left is None and node.right is None: # 到达叶子节点
                res.append(path_sum+node.val)

            dfs(node.left,path_sum+node.val)
            dfs(node.right,path_sum+node.val)

        dfs(root,0)
        return targetSum in res

忘了还能剪枝

class Solution:
    def hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool:
        res=[False]
        def dfs(node,path_sum):
            if res[0]:
                return
            if node is None:
                return
            if node.left is None and node.right is None: # 到达叶子节点
                if path_sum+node.val==targetSum:
                    res[0]=True


            dfs(node.left,path_sum+node.val)
            dfs(node.right,path_sum+node.val)

        dfs(root,0)
        return res[0]

113. Path Sum II

还是 dfs

class Solution:
    def pathSum(self, root: Optional[TreeNode], targetSum: int) -> List[List[int]]:
        res=[]

        if root is None:
            return res

        def dfs(node,path,path_sum):
            if node is None:
                return
            if node.left is None and node.right is None:
                if path_sum+node.val==targetSum:
                    res.append(path+[node.val])
                    return

            dfs(node.left,path+[node.val],path_sum+node.val)
            dfs(node.right,path+[node.val],path_sum+node.val)

        dfs(root,[],0)
        return res

114. Flatten Binary Tree to Linked List

dlr 遍历,之前背的 one liner 不实用,背这个

class Solution:
    def flatten(self, root: TreeNode) -> None:
        """
        Do not return anything, modify root in-place instead.
        """
        def dlr(node):
            if not node:
                return

            tmp=node.right
            node.right=dlr(node.left)
            node.left=None

            curr=node
            while curr.right:
                curr=curr.right

            curr.right=dlr(tmp)
            return node

        dlr(root)

116. Populating Next Right Pointers in Each Node

基础的 level order

class Solution:
    def connect(self, root: 'Optional[Node]') -> 'Optional[Node]':
        if not root:
            return root

        queue=[root]
        while queue:
            new_queue=list()
            for idx in range(len(queue)-1):
                queue[idx].next=queue[idx+1]
                if queue[idx].left:
                    new_queue.append(queue[idx].left)
                if queue[idx].right:
                    new_queue.append(queue[idx].right)
            if queue[-1].left:
                new_queue.append(queue[-1].left)
            if queue[-1].right:
                new_queue.append(queue[-1].right)
            queue=new_queue
        return root

117. Populating Next Right Pointers in Each Node II

"""
# Definition for a Node.
class Node:
    def __init__(self, val: int = 0, left: 'Node' = None, right: 'Node' = None, next: 'Node' = None):
        self.val = val
        self.left = left
        self.right = right
        self.next = next
"""

class Solution:
    def connect(self, root: 'Node') -> 'Node':
        if not root:
            return root
        queue=[root]

        while queue:
            new_queue=list()
            last_node=None
            for node in queue:
                if last_node is not None:
                    last_node.next=node

                if node.left:
                    new_queue.append(node.left)
                if node.right:
                    new_queue.append(node.right)
                last_node=node

            queue=new_queue

        return root

118. Pascal’s Triangle

level order

class Solution:
    def generate(self, numRows: int) -> List[List[int]]:
        res=[]

        level=[1]
        for i in range(numRows):
            res.append(level)

            next_level=[]
            for i in range(len(level)-1):
                next_level.append(level[i]+level[i+1])

            level=[1]+next_level+[1]
        return res

119. Pascal’s Triangle II

level order

class Solution:
    def getRow(self, rowIndex: int) -> List[int]:
        res=[1]
        for i in range(rowIndex):
            new_res=[]
            for idx in range(len(res)-1):
                new_res.append(res[idx]+res[idx+1])

            res=[1]+new_res+[1]

        return res

120. Triangle

比较大小的,一般用 bfs 而不是 dfs,也就是 level order

class Solution:
    def minimumTotal(self, triangle) -> int:
        queue = triangle[0]

        for line in triangle:

            if len(line) == 1:
                continue
            new_queue = []
            for idx in range(len(queue) - 1):
                new_queue.append(line[idx+1] + min(queue[idx], queue[idx + 1]))
            queue = [queue[0] + line[0]] + new_queue + [queue[-1] + line[-1]]
        return min(queue)

121. Best Time to Buy and Sell Stock

思路1(抄的):站在每一天,看之前哪天买最合适

class Solution:
    def maxProfit(self, prices) -> int:
        min_price = 100000
        res = 0
        for p in prices:
            if p < min_price:
                min_price = p
            else:
                res = max(res, p - min_price)
        return res

思路2(想的)

  • 有点儿像接水的那个题
  • 自然想到双指针
  • 左边追求最小,右边追求最大。如果 left<right,就都移动;否则,分裂为2种情况,用递归
  • (不好想),因为两边追求的是两个方向,因此都从左边出发,向同一个方向走。代码和上一个思路一样了

122. Best Time to Buy and Sell Stock II

简单,每天都买卖一次

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        profit = 0
        for idx in range(len(prices) - 1):
            if prices[idx + 1] > prices[idx]:
                profit += (prices[idx + 1] - prices[idx])

        return profit

125. Valid Palindrome

class Solution:
    def isPalindrome(self, s: str) -> bool:
        s=[i for i in s.lower() if 97<=ord(i)<=122 or 48<=ord(i)<=57]
        return s==s[::-1]

129. Sum Root to Leaf Numbers

!!!这题不是公式里面的 dfs/bfs 类题目,而是更基本的树上的递归问题

class Solution:
    def sumNumbers(self, root: TreeNode) -> int:
        def myfunc(node,sum_):
            if node is None:
                return 0

            sum_+=node.val
            if node.left is None and node.right is None:
                return sum_            

            return myfunc(node.left,10*sum_)+myfunc(node.right,10*sum_)
        return myfunc(root,0)

131. Palindrome Partitioning

dfs+cache,不过效率好差,双击败5%

class Solution:
    def partition(self, s: str):
        cache = dict()

        def dfs(string):
            if string in cache:
                return cache[string]

            if len(string) == 1:
                res = {(string,)}
            else:
                res = set()
                if string == string[::-1]:
                    res.add((string,))
                for i in range(1, len(string)):
                    res.update({part1 + part2 for part1 in dfs(string[:i]) for part2 in dfs(string[i:])})
            cache[string] = res
            return res

        tmp = dfs(s)
        return [list(i) for i in tmp]

133. Clone Graph

作弊

copy.deepcopy(node)

显然 dfs+cache

  • graph 要注意回环的情况,否则会 max recursion
  • 回环后,不要直接new一个node,而是查看是否已有(在cache中)

class Solution:
    def cloneGraph(self, node) :
        if node is None:
            return None

        root_old = node
        root_new = Node(val=node.val)
        cache = dict()

        def dfs(node, node_new):
            if node.val in cache:
                return

            cache[node.val]=node_new

            for neighbor in node.neighbors:
                neighbor_new=cache.get(neighbor.val,Node(neighbor.val))
                node_new.neighbors.append(neighbor_new)
                dfs(neighbor, neighbor_new)

        dfs(root_old, root_new)

        return root_new

134. Gas Station

  • gas=gas-cost,然后只在gas上面判断即可。
  • 暴力循环超时
# 超时
class Solution:
    def canCompleteCircuit(self, gas: List[int], cost: List[int]) -> int:
        for idx in range(len(gas)):
            gas[idx]-=cost[idx]

        def is_good(nums):
            residu=0
            for num in nums:
                residu+=num
                if residu<0:
                    return False
            return True

        for idx in range(len(gas)):
            if gas[idx]<0:
                continue
            if is_good(gas[idx:]+gas[:idx]):
                return idx

        return -1

剪枝:

  • gas[idx]<0 一定不成立
  • 如果 gas[idx] 不成立,并且 gas[idx+1]>0,那么 idx+1 也不成立,直到遇到 gas[idx+n]<0
  • 注意处理0的情况
class Solution:
    def canCompleteCircuit(self, gas, cost) -> int:
        for idx in range(len(gas)):
            gas[idx] -= cost[idx]

        if sum(gas) < 0:
            return -1

        def is_good(nums):
            residu = 0
            for num in nums:
                residu += num
                if residu < 0:
                    return False
            return True

        skip = False
        for idx in range(len(gas)):
            if skip:
                if gas[idx] >= 0:
                    continue
                else:
                    skip = False
                    continue

            if gas[idx] < 0:
                continue

            if is_good(gas[idx:] + gas[:idx]):

                return idx
            else:
                skip = True

        return -1

139. Word Break

递归+cache,beat98%&95%

这个题 其实应该用 Trie 进一步优化,不过这次没这么做

class Solution:
    def wordBreak(self, s: str, wordDict) -> bool:
        cache = dict()
        max_len = max(len(i) for i in wordDict)

        def dfs(idx):
            if idx in cache:
                return cache[idx]
            res = False
            if s[:idx + 1] in wordDict:
                res = True
            else:
                for i in range(max(idx - max_len, 0), idx):
                    if dfs(i) and s[i + 1:idx + 1] in wordDict:
                        res = True
                        break
            cache[idx] = res
            return res

        dfs(len(s) - 1)
        return cache[len(s) - 1]

140. Word Break II

和上一个题思路一样。

与上一个题一样,都是调 idx 调了好半天

class Solution:
    def wordBreak(self, s: str, wordDict):
        cache = dict()
        max_len = max(len(i) for i in wordDict)

        def dfs(idx):
            if idx in cache:
                return cache[idx]

            res = []
            if idx == 0:
                res = [[]]
            else:
                for i in range(max(0, idx - max_len - 1), idx):

                    if s[i:idx] in wordDict:
                        for item in dfs(i):
                            res.append(item + [s[i:idx]])

            cache[idx] = res
            return res

        dfs(len(s))
        return [' '.join(i) for i in cache[len(s)]]

141. Linked List Cycle

快慢指针

class Solution:
    def hasCycle(self, head: Optional[ListNode]) -> bool:
        pointer1,pointer2=head,head
        while pointer1 and pointer2 and pointer2.next:
            pointer1=pointer1.next
            pointer2=pointer2.next.next
            if pointer1 is pointer2:
                return True


        return False

142. Linked List Cycle II

快慢指针太技巧了,用hash表存一下即可

class Solution:
    def detectCycle(self, head: ListNode) -> ListNode:
        cache,curr,pos=set(),head,0
        while curr:
            if curr in cache:
                return curr
            cache.add(curr)
            curr=curr.next
        return None

143. Reorder List

思路

  1. 做成两个LinkedList,
  2. 其中一个按题目要求反转
  3. 然后合并

???

146. LRU Cache

借助队列,判断哪些是最近未访问过的

class Queue:
    def __init__(self,capacity):
        self.capacity=capacity
        self.queue=list()
    def visit(self,key):
        if key in self.queue:
            self.queue.remove(key)

        self.queue.append(key)
        droped=None
        if len(self.queue)>self.capacity:
            droped=self.queue[0]
            self.queue=self.queue[1:]
        return droped



class LRUCache:
    def __init__(self, capacity: int):
        self.cache=dict()
        self.queue=Queue(capacity)

    def get(self, key: int) -> int:
        if key in self.cache:
            self.queue.visit(key)
            return self.cache[key]
        else:
            return -1


    def put(self, key: int, value: int) -> None:
        droped=self.queue.visit(key)
        if droped is not None:
            del self.cache[droped]

        self.cache[key]=value

用 OrderedDict,简直是量身定做

from collections import OrderedDict

class LRUCache:
    def __init__(self, capacity: int):
        self.capacity=capacity
        self.cache=OrderedDict()

    def get(self, key: int) -> int:
        if key in self.cache:
            self.cache.move_to_end(key=key)
            return self.cache[key]
        return -1

    def put(self, key: int, value: int) -> None:
        if key in self.cache:
            self.cache[key]=value
            self.cache.move_to_end(key)
        else:
            self.cache[key]=value
            if len(self.cache)>self.capacity:
                self.cache.popitem(last=False)

151. Reverse Words in a String

return ' '.join(i for i in  s.split(' ')[::-1] if i)

160. 相交链表

简单

class Solution:
    def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
        cache=set()
        while headA:
            cache.add(headA)
            headA=headA.next

        while headB:
            if headB in cache:
                return headB
            headB=headB.next

        return None

165. Compare Version Numbers

class Solution:
    def compareVersion(self, version1: str, version2: str) -> int:
        version1=[int(i) for i in version1.split('.')]
        version2=[int(i) for i in version2.split('.')]

        while len(version1)>1 and version1[-1]==0:
            version1.pop()
        while len(version2)>1 and version2[-1]==0:
            version2.pop()

        if version1>version2:
            return 1
        elif version1<version2:
            return -1
        else:
            return 0

167. Two Sum II - Input Array Is Sorted

二分法。 边界条件有些烦人

class Solution:

    def twoSum(self, numbers, target: int):
        curr, left, right = 0, 1, len(numbers) - 1

        while curr < right:

            target_1 = target - numbers[curr]
            while left < right:
                # print(curr, left, right)
                mid = (left + right) // 2
                if numbers[mid] < target_1:
                    left = mid + 1
                elif numbers[mid] > target_1:
                    right = mid - 1
                else:
                    return curr + 1, mid + 1

            if numbers[left] == target_1:
                return curr + 1, left + 1

            curr += 1
            left = curr + 1
        return -1

168. Excel Sheet Column Title

恶心的边界条件

class Solution:
    def convertToTitle(self, columnNumber: int) -> str:
        dictionary = {i: chr(i + 65) for i in range(26)}

        res = ''
        while columnNumber:
            columnNumber -= 1
            columnNumber, tmp1 = divmod(columnNumber, 26)
            res = dictionary[tmp1]+res

        return res

171. Excel Sheet Column Number

class Solution:
    def titleToNumber(self, columnTitle: str) -> int:
        dictionay={chr(i+65):i for i in range(26)}
        res=0
        for i in columnTitle:
            res*=26
            res+=(dictionay[i]+1)
        return res

169. Majority Element

import collections
class Solution:
    def majorityElement(self, nums: List[int]) -> int:
        counter = collections.Counter(nums)
        return counter.most_common(1)[0][0]

172. Factorial Trailing Zeroes

思路:

  • 0的数量取决于2和5的数量
  • 无论什么情况下,2的数量肯定是够的。因此只需要计算5的数量
  • 对于k,用k%5 来计算5的数量
class Solution:
    def trailingZeroes(self, n: int) -> int:
        def get_5(i):
            num_5 = 0
            while i:
                i, k2 = divmod(i, 5)
                if k2:
                    return num_5
                num_5 += 1


        res = 0
        for i in range(1, n + 1):
            res += get_5(i)

        return res

187. Repeated DNA Sequences

class Solution:
    def findRepeatedDnaSequences(self, s: str) -> List[str]:
        res=set()
        tmp=set()
        for i in range(len(s)-9):
            if s[i:i+10] in tmp:
                res.add(s[i:i+10])
            else:
                tmp.add(s[i:i+10])           

        return list(res)

190. Reverse Bits

class Solution:
    def reverseBits(self, n: int) -> int:
        n_str=bin(n)[2:]
        n_str='0'*(32-len(n_str))+n_str
        return int(n_str[::-1],2)

这题还有更高级的方案:

  • 本质上是循环把n的低位放到res的高位
res, i = 0, 32
while i:
    res <<= 1
    res += (n & 1)
    n >>= 1
    i -= 1
res

191. Number of 1 Bits

cnt = 0
while n:
    n = n & (n - 1)
    cnt += 1

192-195 bash题

192. Word Frequency cat words.txt| tr -s ' ' '\n' | sort | uniq -c | sort -r | awk '{print $2, $1}'

193. Valid Phone Numbers
grep -P '^([0-9]{3}-|\([0-9]{3}\) )[0-9]{3}-[0-9]{4}$' file.txt

194. Transpose File

python3 -c "
a = [i.split() for i in open('file.txt', 'r')]
print('\n'.join(' '.join(i) for i in zip(*a)))
"

195. Tenth Line

python3 -c "
with open('file.txt', 'r') as f:
    for i in range(9):
        f.readline()

    print(f.readline().replace('\n', ''))
"

198. House Robber

dfs+cache 套公式

class Solution:
    def rob(self, nums: List[int]) -> int:

        len_num=len(nums)
        cache=dict()

        def dfs(idx):
            if idx in cache:
                return cache[idx]

            res=None
            if idx==len_num-1:
                res=nums[idx]

            elif idx==len_num-2:
                res=nums[idx]
            else:
                res= nums[idx]+max([dfs(i) for i in range(idx+2,len_num)])

            cache[idx]=res
            return res

        return max([dfs(i) for i in range(len_num)])

199. Binary Tree Right Side View

class Solution:
    def rightSideView(self, root: Optional[TreeNode]) -> List[int]:

        res=[]
        if not root:
            return res
        queue=[root]
        while queue:
            res.append(queue[-1].val)
            new_queue=list()
            for node in queue:
                if node.left:
                    new_queue.append(node.left)
                if node.right:
                    new_queue.append(node.right)

            queue=new_queue

        return res

您的支持将鼓励我继续创作!