20211016leetcode【3,79,17need again】

leetcode 刷题记录

  • 一刷leetcode
    • 10.16日
      • 1、二叉树的层序遍历(done)
      • 2、从前序与中序遍历序列构造二叉树(done)
      • 3、二叉树展开为链表(……`need again`)
      • 4、两数之和-哈希表(done)
      • 5、有序两数之和-双指针法(done)
      • 6、三数之和-双指针法(done,排序+双指针)
      • 7、盛最多水容器-双指针法(done)
      • 8、对称二叉树-递归(done)
      • 9、二叉树最大深度-递归(done)
      • 10、买卖股票的最佳时机(done)
    • 10.17日
      • 1、电话号码的数组组合(……`need again`)
      • 2、删除链表的倒数第 N 个结点(done)
      • 3、有效括号(done)
      • 4、合并两个有序链表(done)
      • 5、搜索旋转排序数组(done)
      • 6、无重复字符的最长子串(……`need again`)
    • 10.19日
      • 1、最小路径和(done)
      • 2、二叉树中序遍历(done)
      • 3、验证二叉搜索树-(done)
      • 4、最长连续序列(……`need again`)
      • 5、不同的二叉搜索树-动态规划(……不会)
    • 10.30日
      • 1、子集-(……need again)
      • 2、单词搜索-回溯(……`不会`)
      • 3、颜色分类(……need again)
      • 4、编辑距离(done)
      • 5、不同路径(done)
      • 6、合并区间-排序(done)
      • 7、跳跃游戏-贪心(……不会)
      • 8、最大子序和-贪心&动态规划(done)
      • 9、最长回文子串-动态规划(done)
      • 10、旋转图像(done)
    • 10.31日
      • 1、全排列(……need again)
      • 2、字母异位词分组-(……need again)
      • 3、组合总和-(……不会)
      • 4、在排序数组中查找元素的第一个和最后一个位置-(……不会)
      • 5、单词拆分-(……need again)
      • 6、下一个排列-(……不会)
      • 7、两数相加-(done)
      • 8、最小的K个数-(……need again)

一刷leetcode

10.16日

1、二叉树的层序遍历(done)

102二叉树的层序遍历

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def levelOrder(self, root: TreeNode) -> List[List[int]]:
        results = []
        if not root:
            return results
        
        from collections import deque
        que = deque([root])

        while que:
            result = []
            for _ in range(len(que)):
                cur = que.popleft()
                result.append(cur.val)
                if cur.left:
                    que.append(cur.left)
                if cur.right:
                    que.append(cur.right)
            results.append(result)
        return results

2、从前序与中序遍历序列构造二叉树(done)

105从前序与中序遍历序列构造二叉树
⚠️ preorder_left下标不是从0开始,而是1。

class Solution:
    def buildTree(self, preorder: List[int], inorder: List[int]) -> TreeNode:
        # 第一步: 特殊情况讨论: 树为空. 或者说是递归终止条件
        if not preorder:
            return None 
        
        # 第二步: 前序遍历的第一个就是当前的中间节点. 
        root_val = preorder[0]
        root = TreeNode(root_val)

        # 第三步: 找切割点. 
        separator_idx = inorder.index(root_val)

        # 第四步: 切割inorder数组. 得到inorder数组的左,右半边. 
        inorder_left = inorder[:separator_idx]
        inorder_right = inorder[separator_idx+1:]

        # 第五步: 切割preorder数组. 得到preorder数组的左,右半边.
        # ⭐️ 重点1: 中序数组大小一定跟前序数组大小是相同的. 
        preorder_left = preorder[1:1 + len(inorder_left)]
        preorder_right = preorder[1 + len(inorder_left):]

        #递归
        root.left = self.buildTree(preorder_left,inorder_left)
        root.right = self.buildTree(preorder_right,inorder_right)
        
        return root 

3、二叉树展开为链表(……need again

114二叉树展开为链表
前序遍历ans.append()的是root,不是root.val

class Solution:
    def flatten(self, root: TreeNode) -> None:
        ans = []

        #前序遍历
        def preOrder(root):
            if root:
                ans.append(root)    #是root,不是root.val
                preOrder(root.left)
                preOrder(root.right)
        
        preOrder(root)
        for i in range(1,len(ans)):
            pre,cur = ans[i-1],ans[i]
            pre.left = None
            pre.right = cur
        return ans

4、两数之和-哈希表(done)

1两数之和

def twoSum(nums, target):
    s = dict()
    for i, j in enumerate(nums):  #i下表,j值
        if target - j in s:       #不要使用s.values()
            return [s[traget-j], i]
        else:
            s[j] = i    #hash表存储的是值,下表,方便区下标
    return []

5、有序两数之和-双指针法(done)

167两数之和-有序

def twoSum(numbers, target):
    # 双指针法
    i, j = 0, len(numbers) - 1
    while i < j:   #有序,左边 < 右边
        if numbers[i] + numbers[j] < target:
           i += 1
        elif numbers[i] + numbers[j] > target:
           j -= 1
        else:
           return [i, j]
    return []

6、三数之和-双指针法(done,排序+双指针)

15 三数之和

class Solution:
    def threeSum(self, nums: List[int]) -> List[List[int]]:
        n = len(nums)
        nums.sort()
        results = []

        for i in range(n):
            if nums[i] > 0: #第一个数大于0,和肯定大于0
                break 
            if i > 0 and nums[i] == nums[i-1]: #第一个数去重
                continue
            left = i+1
            right = n-1
            while left < right:
                total = nums[i] + nums[left] + nums[right]
                if total > 0:
                    right -= 1
                elif total < 0:
                    left += 1
                else:
                    results.append([nums[i], nums[left],nums[right]])
                    while left < right and nums[left] == nums[left+1]: left += 1
                    while left < right and nums[right] == nums[right-1]: right -= 1
                    left += 1
                    right -= 1
        return results

7、盛最多水容器-双指针法(done)

11 盛最多水的容器
如果我们移动数字较大的那个指针,那么前者「两个指针指向的数字中较小值」不会增加,后者「指针之间的距离」会减小,那么这个乘积会减小。因此,我们移动数字较大的那个指针是不合理的。因此,我们移动 数字较小的那个指针。

def maxArea(height):
    l, r = 0, len(height) - 1
    ans = 0
    while l < r:
        s = (r - l) * min(height[l], height[r])
        ans = max(ans, s)
        # 移动短的那根
        if height[l] <= height[r]:
            l += 1
        elif height[l] > height[r]:
            r -= 1
    return ans

8、对称二叉树-递归(done)

101对称二叉树

class Solution:
    def isSymmetric(self, root: TreeNode) -> bool:
        def im(l,r):
            if l == None and r == None:  #左右子树都为空
                return True
            
            if l == None or r == None:  #一个为空,一个非空
                return False
             #它们的两个根结点具有相同的值 && 每个树的右子树都与另一个树的左子树镜像对称
            return l.val == r.val and im(l.right,r.left) and im(l.left,r.right)
        
        return im(root.left,root.right)

9、二叉树最大深度-递归(done)

104二叉树最大深度

class Solution:
    def maxDepth(self, root: TreeNode) -> int:
        if not root :
            return 0
        #depth(root.left)辅助函数可省略
        return 1 + max(self.maxDepth(root.left),self.maxDepth(root.right))

10、买卖股票的最佳时机(done)

121买卖股票的最佳时机

def maxProfit(prices):
    #r变量记录一个历史最低价格,第 i 天卖出股票能得到的利润就是 prices[i] - r
    #我们只需要遍历价格数组一遍,记录历史最低点,然后在每一天考虑这么一个问题:如果我是在历史最低点买进的,那么我今天卖出能赚多少钱?当考虑完所有天数之时,我们就得到了最好的答案
    minprice = prices[0]
    maxprofit = 0
    for price in prices:
        maxprofit = max(price - minprice, maxprofit)
        minprice = min(price, minprice)
    return maxprofit

10.17日

1、电话号码的数组组合(……need again

17电话号码的组合

class Solution:
    def letterCombinations(self, digits: str) -> List[str]:
        if not digits:
            return list()
        
        phoneMap = {
            "2": "abc",
            "3": "def",
            "4": "ghi",
            "5": "jkl",
            "6": "mno",
            "7": "pqrs",
            "8": "tuv",
            "9": "wxyz",
        }

        def backtrack(index: int):
            if index == len(digits):
                combinations.append("".join(combination))
            else:
                digit = digits[index]
                for letter in phoneMap[digit]:
                    combination.append(letter)
                    backtrack(index + 1)
                    combination.pop()

        combination = list()
        combinations = list()
        backtrack(0)
        return combinations

2、删除链表的倒数第 N 个结点(done)

19. 删除链表的倒数第 N 个结点
1、初始时 first 和 second 均指向头节点。我们首先使用 first 对链表进行遍历,遍历的次数为 n。此时,first 和 second 之间间隔了 n−1 个节点,即 first 比 second 超前了 n 个节点。
2、在这之后,我们同时使用 first 和 second 对链表进行遍历。当 first 遍历到链表的末尾(即 first 为空指针)时,second 恰好指向倒数第 n 个节点。
3、如果我们能够得到的是倒数第 n 个节点的前驱节点而不是倒数第 n 个节点的话,删除操作会更加方便。因此我们可以考虑在初始时将 second 指向哑节点,其余的操作步骤不变。这样一来,当 first 遍历到链表的末尾时,second 的下一个节点就是我们需要删除的节点。

class Solution:
    def removeNthFromEnd(self, head: ListNode, n: int) -> ListNode:
        dummy = ListNode(0,head)
        l = dummy  #慢指针指向哑节点

        f = head
      
        for i in range(n):
            f = f.next
        
        while f :
            f = f.next
            l = l.next

        l.next = l.next.next #删除
        return dummy.next

3、有效括号(done)

  • 如果 c 是左括号,则入栈 push;
  • 否则通过哈希表判断括号对应关系,若 stack 栈顶出栈括号 stack.pop() 与当前遍历括号 c 不对应,则提前返回 false。

20. 有效的括号

class Solution:
    def isValid(self, s: str) -> bool:
    	if len(s) % 2 == 1:
            return False
            
        d = {
        ')': '(',
        '}': '{',
        ']': '['
        }
        stack = []
        for i in s:
            if i in d.keys() and stack != [] and d[i] == stack[-1]:
                stack.pop()
            else:
                stack.append(i)
        return not stack

4、合并两个有序链表(done)

21. 合并两个有序链表
首先,我们设定一个==哑节点 prehead ==,这可以在最后让我们比较容易地返回合并后的链表。我们维护一个 prev 指针,我们需要做的是调整它的 next 指针。然后,我们重复以下过程,直到 l1 或者 l2 指向了 null :如果 l1 当前节点的值小于等于 l2 ,我们就把 l1 当前的节点接在 prev 节点的后面同时将 l1 指针往后移一位。否则,我们对 l2 做同样的操作。不管我们将哪一个元素接在了后面,我们都需要把 prev 向后移一位。

class Solution:
    def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:
    	#哑节点
        dummy = ListNode(0)
        pre = dummy

        while l1 and l2:
            if l1.val <= l2.val:
                pre.next = l1
                l1 = l1.next
            else:
                pre.next = l2
                l2 = l2.next
            pre = pre.next

        pre.next = l1 if l1  else l2
        return dummy.next  #注意是dummy.next而非pre.next

5、搜索旋转排序数组(done)

33. 搜索旋转排序数组

  • 在常规二分查找的时候查看以当前 mid 为分割位置分割出来的两个部分 [0, mid - 1] 和 [mid + 1, r]哪个部分是有序的
  • 如果 [0, mid - 1] 是有序数组,且 target 的大小属于[nums[0],nums[mid]),则我们应该将搜索范围缩小至[0, mid - 1],否则在 [mid + 1, r] 中寻找。
  • 如果 [mid + 1, r] 是有序数组,且 target的大小属于[nums[mid+1],nums[r]],则我们应该将搜索范围缩小至 [mid + 1, r],否则在 [l, mid - 1] 中寻找。
class Solution:
    def search(self, nums: List[int], target: int) -> int:
        #二分法
        if not nums:
            return -1
         
        l, r = 0,len(nums) -1 
        while l <= r :
            mid = (l + r)//2
            if nums[mid] == target: 
                return mid
            elif nums[l] <= nums[mid]:            #说明左边有序,进行二分查找,区间[0,mid-1]
                if nums[l] <= target < nums[mid]:  #target在[0,mid-1]中
                    r = mid - 1         
                else:                  #target不在[0,mid-1]中,则查找右区间
                    l = mid + 1
            else:  #说明右边有序,进行二分查找,区间[mid+1,r]
                if nums[mid] < target <= nums[r]:  #target在[mid+1,r]中
                    l = mid + 1
                else:             #否则查找左区间     
                    r = mid - 1  
        return -1

6、无重复字符的最长子串(……need again)

3. 无重复字符的最长子串
while s[r] in cur: 要用while而不是if

class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        cur, res = [], 0
        for r in range(len(s)):
            while s[r] in cur: 
                cur.pop(0) # 左边出
            cur.append(s[r]) # 右侧无论如何都会进入新的
            res = max(len(cur),res)
        return res
class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        ans = set() 
        n = len(s)
        start = 0
        max_len = 0

        for j in range(n):
            while s[j] in ans:
                ans.remove(s[start])
                start += 1
            ans.add(s[j])
            max_len = max(max_len,j-start+1)
        return max_len

10.19日

1、最小路径和(done)

64 最小路径和

  • 状态定义:设dp为大小 m×n 矩阵,其中 dp[i][j]的值代表直到走到 (i,j)的最小路径和。
  • 转移方程:当前单元格 (i,j)只能从左方单元格 (i-1,j)或上方单元格 (i,j−1)
    走到,因此只需要考虑矩阵左边界和上边界。走到当前单元格 (i,j)的最小路径和 = “从左方单元格 (i-1,j)与 从上方单元格(i,j-1)走来的 两个最小路径和中较小的 ” + 当前单元格值 grid[i][j] 。具体分为以下4 种情况:
    当左边和上边都不是矩阵边界时: 即当i != 0,j != 0时,dp[i][j] = min(dp[i - 1][j], dp[i][j - 1]) + grid[i][j];
    当只有左边是矩阵边界时: 只能从上面来,即当i = 0, j != 0时, dp[i][j] = dp[i][j - 1] + grid[i][j];
    当只有上边是矩阵边界时: 只能从左面来,即当i != 0, j = 0时, dp[i][j] = dp[i - 1][j] + grid[i][j];
    当左边和上边都是矩阵边界时: 即当i=0,j=0时,其实就是起点, dp[i][j] = grid[i][j];
  • 初始状态:dp初始化即可,不需要修改初始 0 值。
class Solution:
    def minPathSum(self, grid: List[List[int]]) -> int:
        if not grid:
            return 0

        dp = [[0] * len(grid[0]) for _ in range(len(grid))]
        
        for i in range(len(grid)):
            for j in range(len(grid[0])):
                if i==0 and j== 0:
                    dp[i][j] = grid[0][0]
                elif i==0:
                    dp[0][j] = dp[0][j-1] + grid[0][j]
                elif j== 0:
                    dp[i][0] = dp[i-1][0] + grid[i][0]
                else:
                    dp[i][j] = min(dp[i-1][j],dp[i][j-1]) + grid[i][j]
        return dp[-1][-1]

2、二叉树中序遍历(done)

94 二叉树中序遍历

class Solution:
    def inorderTraversal(self, root: TreeNode) -> List[int]:
        res = []
    
        def dfs(root):
            if not root:
                return
            # 按照 左-根-右的方式遍历	
            dfs(root.left)
            res.append(root.val)
            dfs(root.right)
        dfs(root)
        return res

3、验证二叉搜索树-(done)

98 验证二叉搜索树

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

        def dfs(root):
            if not root:
                return 
            
            dfs(root.left)
            res.append(root.val)
            dfs(root.right)
            return res
        
        d = dfs(root)
        return d == sorted(d) and len(d) == len(set(d))

4、最长连续序列(……need again)

128 最长连续序列

class Solution:
    def longestConsecutive(self, nums: List[int]) -> int:
        longest_streak = 0
        num_set = set(nums)     #去重

        for num in num_set:
            if num - 1 not in num_set: #判断num-1是否在nums中
                current_num = num
                current_streak = 1

                while current_num + 1 in num_set: #判断num+1是否在nums中
                    current_num += 1
                    current_streak += 1

                longest_streak = max(longest_streak, current_streak)

        return longest_streak

5、不同的二叉搜索树-动态规划(……不会)

96 不同的二叉搜索树

10.30日

1、子集-(……need again)

78 子集

class Solution:
    def subsets(self, nums: List[int]) -> List[List[int]]:
        result = [[]]
        for i in nums:
            n = len(result)
            for j in range(n):
                result.append(result[j] + [i])
        return result

2、单词搜索-回溯(……不会

79 单词搜索

class Solution:
    def exist(self, board: List[List[str]], word: str) -> bool:
        #当前元素在矩阵 board 中的行列索引 i 和 j ,当前目标字符在 word 中的索引 k
        def dfs(i, j, k):
            if not 0 <= i < len(board) or not 0 <= j < len(board[0]) or board[i][j] != word[k]: return False
            if k == len(word) - 1: 
                return True
            # 将 board[i][j] 修改为 空字符 '' ,代表此元素已访问过,防止之后搜索时重复访问
            board[i][j] = ''
            res = dfs(i + 1, j, k + 1) or dfs(i - 1, j, k + 1) or dfs(i, j + 1, k + 1) or dfs(i, j - 1, k + 1)
            #将 board[i][j] 元素还原至初始值,即 word[k]
            board[i][j] = word[k]
            return res

        for i in range(len(board)):
            for j in range(len(board[0])):
                if dfs(i, j, 0): return True
        return False

3、颜色分类(……need again)

75 颜色分类

  • 如果找到了0,则将其与nums[p0]进行交换,并将p0向后移动一个位置;
  • 如果找到了2,那么将其与nums[p2]进行交换,并将 p2向前移动一个位置。(不能用if)
def sortColors(nums):
    p0,p2 = 0,len(nums)-1
    i = 0
    # 当我们将nums[i] 与nums[p2] 进行交换之后,新的nums[i] 可能仍然是2也可能是 0。然而此时我们已经结束了交换,开始遍历下一个元素nums[i+1],不会再考虑 nums[i]了,
    while i <= p2:
        while i <= p2 and nums[i] == 2: #不能使用if
           nums[i],nums[p2] = nums[p2], nums[i]
           p2 -= 1
        if nums[i] == 0:
           nums[i],nums[p0] = nums[p0],nums[i]
           p0 += 1
        i += 1
    return nums

4、编辑距离(done)

72 编辑距离

class Solution:
    def minDistance(self, word1: str, word2: str) -> int:
        m = len(word1)
        n = len(word2)
        dp = [[float('inf') for _ in range(n + 1)] for _ in range(m + 1)]
        # 初始化
        for i in range(m + 1):
            dp[i][0] = i
        for i in range(n + 1):
            dp[0][i] = i

        # 状态转移
        # i , j 代表 word1, word2 对应位置的 index
        for i in range(1, m + 1):
            for j in range(1, n + 1):
                # 如果word1[:i][-1]==word2[:j][-1]
                if word1[i - 1] == word2[j - 1]:
                    dp[i][j] = dp[i - 1][j - 1]
                # 否则从三种状态中选一个最小的然后 +1
                else:
                    dp[i][j] = min(dp[i - 1][j - 1], min(dp[i - 1][j], dp[i][j - 1])) + 1
        return dp[-1][-1]

5、不同路径(done)

62 不同路径

def uniquePaths(m, n):
    dp = [[0]*n for _ in range(m)]

    #初始化
    for i in range(n):
       dp[0][i] = 1
    for i in range(m):
       dp[i][0] = 1
    
    for i in range(1,m):
        for j in range(1,n):
            dp[i][j] = dp[i-1][j] + dp[i][j-1]
    return dp[-1][-1]

6、合并区间-排序(done)

56 合并区间
将列表中的区间按照左端点升序排序。然后我们将第一个区间加入 merged 数组中,并按顺序依次考虑之后的每个区间:

  • 如果当前区间的左端点在数组 merged 中最后一个区间的右端点之后,那么它们不会重合,我们可以直接将这个区间加入数组 merged的末尾;
  • 否则,它们重合,我们需要用当前区间的右端点更新数组 merged 中最后一个区间的右端点,将其置为二者的较大值。
def merge(intervals):
    intervals.sort(key=lambda x: x[0])  # #x:x[]字母可以随意修改,排序方式按照中括号[]里面的维度进行排序,[0]按照第一维排序,[1]按照第二维排序,reverse=true表示降序,reverse=false表示逆序。
    merged = []
    for interval in intervals:
        # 如果列表为空,或者当前区间与上一区间不重合,直接添加
        if not merged or merged[-1][-1] < interval[0]:
            merged.append(interval)
        else:
            # 否则的话,我们就可以与上一区间进行合并
            merged[-1][-1] = max(merged[-1][-1], interval[-1])
    return merged

7、跳跃游戏-贪心(……不会)

55 跳跃游戏

class Solution:
    def canJump(self, nums: List[int]) -> bool:
        n, rightmost = len(nums), 0
        for i in range(n):
            if i <= rightmost:
                rightmost = max(rightmost, i + nums[i])
                if rightmost >= n - 1:
                    return True
        return False

8、最大子序和-贪心&动态规划(done)

53 最大子序和
动态规划:若前一个元素大于0,则将其加到当前元素上dp[i] = max(dp[i-1] + nums[i],nums[i])

class Solution:
    def maxSubArray(self, nums: List[int]) -> int:
        if not nums:
            return 0

        dp = [0] * len(nums)
        dp[0] = nums[0]
        maxsum = nums[0]
        for i in range(1,len(nums)):
            dp[i] = max(dp[i-1] + nums[i],nums[i])
            maxsum = max(maxsum,dp[i])
        return maxsum

9、最长回文子串-动态规划(done)

5 最长回文子串

  • 状态:dp[i][j]表示子串s[i:j]是否为回文子串
  • 状态转移方程:dp[i][j]= (s[i] ==s[j] and dp[i+1][j-1])
  • 边界条件:j-1 - (i+1)+1<2 得到j-i + 1 < 4,s[i,j]长度为2或3时不用检查字串是否回文
  • 初始化:dp[i][i]=true
class Solution:
    def longestPalindrome(self, s: str) -> str:
        if len(s) < 2:
            return s
   
        dp = [[False]*len(s) for _ in range(len(s))]
        for i in range(len(s)):
            dp[i][i] = True
            
        maxlen = 1
        begin = 0
        for j in range(len(s)):
            for i in range(j):
                if s[i] == s[j]:
                    if j - i <= 2:
                        dp[i][j] = True
                    if dp[i+1][j-1]:
                        dp[i][j] = True
                # 只要 dp[i][L] == true 成立,就表示子串 s[i:L] 是回文,此时记录回文长度和起始位置
                if dp[i][j] and j-i+1 > maxlen:
                    maxlen = j-i+1
                    begin = i 
        return s[begin:begin+maxlen]

10、旋转图像(done)

48 旋转图像
规律:matrix[i][j] => [j][n-1-i]

class Solution:
    def rotate(self, matrix: List[List[int]]) -> None:
        n = len(matrix)
        matrix_new = [[0]*n for _ in range(n)]
        for i in range(n):
            for j in range(n):
                matrix_new[j][n-1-i]= matrix[i][j]
        matrix[:] = matrix_new #不能 matrix_new = matrix 或 matrix_new = matrix[:] 因为是引用拷贝
        return matrix

10.31日

1、全排列(……need again)

46 全排列

class Solution:
    def permute(self, nums: List[int]) -> List[List[int]]:
        n = len(nums)
        res = []
              
        def backtrack(first = 0):
            # 所有数都填完了
            if first == n:   
                res.append(nums[:])  #nums的拷贝
            for i in range(first, n):
                # 动态维护数组
                nums[first], nums[i] = nums[i], nums[first]
                # 继续递归填下一个数
                backtrack(first + 1)
                # 撤销操作
                nums[first], nums[i] = nums[i], nums[first]
        backtrack()
        return res

2、字母异位词分组-(……need again)

49 字母异位词分组

class Solution:
    def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
         #使用defaultdict,可以给不存在的key给一个默认的初始值
        mp = collections.defaultdict(list) 

        for st in strs:
            counts = [0] * 26
            for ch in st:
                counts[ord(ch) - ord("a")] += 1
            # 需要将 list 转换成 tuple 才能进行哈希
            mp[tuple(counts)].append(st)
        
        return list(mp.values())

3、组合总和-(……不会)

39 组合总和

4、在排序数组中查找元素的第一个和最后一个位置-(……不会)

34 在排序数组中查找元素的第一个和最后一个位置

5、单词拆分-(……need again)

139 单词拆分

class Solution:
    def wordBreak(self, s: str, wordDict: List[str]) -> bool:
        dp = [False] * (len(s) + 1)
        dp[0] = True
        #遍历背包
        for j in range(1,len(s)+1):
            #遍历单词
            for word in wordDict:
                if j >= len(word):
                    dp[j] = dp[j] or  (dp[j- len(word)] and s[j- len(word):j] == word)
        return dp[len(s)]

6、下一个排列-(……不会)

31 下一个排列

7、两数相加-(done)

2 两数相加

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def addTwoNumbers(self, l1: Optional[ListNode], l2: Optional[ListNode]) -> Optional[ListNode]:
        s = 0 #进位
        dummy = ListNode(0)
        pre = dummy

        while s or l1 or l2:
            s += (l1.val if l1 else 0) + (l2.val if l2 else 0)
            pre.next = ListNode(s%10)
            pre = pre.next 

            if l1:
                l1 = l1.next
            if l2:
                l2 = l2.next 
            s //= 10 
        return dummy.next 

8、最小的K个数-(……need again)

40 最小的K个数

class Solution:
    def GetLeastNumbers_Solution(self , input: List[int], k: int) -> List[int]:
        # write code here
        if k > len(input):
            return input
        
        ans = self.mergeSort(input)
        if k <= len(input):
            return ans[:k]
        return []
        
    def mergeSort(self,arr):
        if len(arr) < 2:
            return arr
        
        mid = len(arr)//2
        left = arr[0:mid]
        right = arr[mid:]
        return self.merge(self.mergeSort(left),self.mergeSort(right))
    
    def merge(self,left,right):
        res = []
        while left and right:
            if left[0] <= right[0]:
                res.append(left.pop(0))
            else:
                res.append(right.pop(0))
        while left : res.append(left.pop(0))
        while right : res.append(right.pop(0))
        return res

你可能感兴趣的:(leetcode)