Leetcode题解------Python语言实现

283

class Solution(object):
    def moveZeroes(self, nums):
        i = 0
        zero_num = 0
        while i < len(nums):
            if nums[i] == 0:
                del nums[i]
                zero_num += 1
            else:
                i += 1
        return nums.extend([0]*zero_num)

练习:27 26 80

27. 移除元素

class Solution(object):
    def removeElement(self, nums, val):
        if not nums:
            return 0
        i = 0
        while i < len(nums):
            if nums[i] == val:
                nums[i] = nums[-1] # 题目对顺序无要求 可以避免大量的元素移动
                del nums[-1]
            else:
                i += 1
        return len(nums)

75. 颜色分类

计数排序

class Solution(object):
    def sortColors(self, nums):
        zero, one, two = 0, 0, 0
        for num in nums:
            if num == 0:
                zero += 1
            if num == 1:
                one += 1
            if num == 2:
                two += 1
        for i in range(len(nums)):
            if zero != 0:
                nums[i] = 0
                zero -= 1
            elif one != 0:
                nums[i] = 1
                one -= 1
            else:
                nums[i] = 2

练习:88 215

167. 两数之和 II - 输入有序数组

因为有序所以可以尝试二分查找的思想

class Solution(object):
    def twoSum(self, numbers, target):
        if not numbers:
            return
        low = 0
        high = len(numbers) - 1 
        while low < high:
            if numbers[low] + numbers[high] == target:
                return [low+1, high+1]
            elif numbers[low] + numbers[high] > target:
                high -= 1
            else:
                low += 1
        return            

练习:125 344 345 11

209

复杂度较高重新编写

class Solution(object):
    def minSubArrayLen(self, s, nums):
        if not nums:
            return 0
        if max(nums) >= s:
            return 1
        i, j = 0, 1
        res = []
        while j != len(nums):
            if sum(nums[i:j+1]) >= s:
                res.append(j+1 - i)
                i += 1
            else:
                j += 1
        if not res:
            return 0
        else:
            return min(res)

3. 无重复字符的最长子串

class Solution(object):
    def lengthOfLongestSubstring(self, s):
        if not s:
            return 0
        left, right = 0, -1
        res = 0
        dic = dict()
        while left < len(s):      # 当还有子串时继续滑动
            # 如果right还可以向右滑动并且滑动后的值不重复
            if right+1 < len(s) and s[right+1] not in dic: 
                right += 1
                dic[s[right]] = 1 
                res = max(res, right - left +1) # 
            else:
                del dic[s[left]]       # 如果重复逐个从left删除 直到不重复为止
                left += 1                        
        return res

 

练习:438 76

349. 两个数组的交集

class Solution(object):
    def intersection(self, nums1, nums2):
        if not nums1 or not nums2:
            return []
        return list(set(nums1) & set(nums2))

这两个时间复杂度和空间复杂度几乎相同 

class Solution:
    def intersection(self, nums1, nums2):
        lst = []
        a_set = set(nums1)
        b_set = set(nums2)
        for a in a_set:
            if a in b_set:
                lst.append(a)
        return lst

350. 两个数组的交集 II

class Solution(object):
    def intersect(self, nums1, nums2):
        if not nums1 or not nums2:
            return []
        res = []
        dic1 = dict()
        dic2 = dict()
        for num in nums1:
            if num not in dic1:
                dic1[num] = 1
            else:
                dic1[num] += 1
        for num in nums2:
            if num in dic1:
                if num not in dic2:
                    dic2[num] = 1
                else:
                    dic2[num] += 1
        for num in dic2:
            res.extend([num]*min(dic1[num], dic2[num]))
        return res

练习:136 242 202 290 205 451

1. 两数之和

class Solution(object):
    def twoSum(self, nums, target):
        if not nums:
            return []
        dic = dict()
        for i in range(len(nums)):
# 对于有重复值的特殊情况,若查找成功直接返回,查找失败对索引进行更新,不会影响后续查找
            if target - nums[i] not in dic:  
                dic[nums[i]] = i    
            else:
                return [i, dic[target - nums[i]]]
        return []

练习:15 18 16

454. 四数相加 II

class Solution:
    def fourSumCount(self, A: List[int], B: List[int], C: List[int], D: List[int]) -> int:
        if not A or not B or not C or not D:
            return 0
        dic1 = dict()
        res = 0
        for i in A:
            for j in B:
                if i+j not in dic1:
                    dic1[i+j] = 1
                else:
                    dic1[i+j] += 1     
        for i in C:
            for j in D:
                if -(i+j) in dic1:
        # 对于cd中的1种情况 dic1中有dic1[-(i+j)]种情况与之对应
                    res += dic1[-(i+j)]  
        return res

练习:49

447. 回旋镖的数量

class Solution:
    def distance(self, p1, p2):
        # 注意 a**2 + b**2 比 a*a + b*b 耗时!
        return (p1[0]-p2[0])*(p1[0]-p2[0]) + (p1[1]-p2[1])*(p1[1]-p2[1])
    
    def numberOfBoomerangs(self, points: List[List[int]]) -> int:
        if not points:
            return 0
        res = 0
        for point in points:
            dic = dict()
            for tmp in points:
                if point != tmp:
                    dist = self.distance(point, tmp)
                    if dist not in dic:
                        dic[dist] = 1
                    else:
                        dic[dist] += 1
            for num in dic:
                res += dic[num]*(dic[num]-1) # 等于1 也没有关系 1 *(1-1)= 0
        return res

 

练习:149 719

219. 存在重复元素 II

# 滑动窗口+查找表
class Solution:
    def containsNearbyDuplicate(self, nums, k):
        if len(nums) <= 1:
            return False
        if k <= 0:
            return False
        
        record = set()             # 初始化一个滑动窗口 每次都在该滑动窗口内进行寻找
        for i in range(len(nums)):
            if nums[i] in record:
                return True
            record.add(nums[i])
            if len(record) == k+1: # 超过滑动窗口范围
                record.remove(nums[i- k])
        return False

 

class Solution(object):
    def containsNearbyDuplicate(self, nums, k):
        if not nums:
            return False
        dic = dict()
        for i in range(len(nums)):
            if nums[i] not in dic: # 第一次出现将元素设为key 索引设为value
                dic[nums[i]] = i
            elif abs(dic[nums[i]] - i) <= k: # 不是首次出现 判断是否满足条件
                return True
            else:                  # 不是首次出现 也不满足条件 则更新该key
                dic[nums[i]] = i
        return False

220. 存在重复元素 III

class Solution:
    def containsNearbyAlmostDuplicate(self, nums: List[int], k: int, t: int) -> bool:
        if not nums or k <= 0 or t < 0 or k == 10000:
            return False
        record = dict()             # 滑动窗口
        for i in range(len(nums)):
            if record:              # 对滑动窗口的值进行判断,如果满足绝对值最大为t 则返回
                for num in record:
                    if abs(nums[i] - record[num]) <= t:
                        return True
            # 模拟滑动窗口的移动
            record[i] = nums[i]     # 不满足条件就后移一位放入滑动窗口
            if len(record) == k+1:  # 判断加入新的值后 滑动窗口的范围是否 超了
                del record[i-k]     # 如果超了 删除最后一位        
        return False

206. 反转链表

class Solution:
    def reverseList(self, head: ListNode) -> ListNode:
        pre = None
        cur = head
        while cur:
            tmp = cur.next
            cur.next = pre
            pre= cur
            cur = tmp
        return pre

 

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def reverseList(self, head):
        if not head or not head.next:
            return head
        pHead = ListNode(0)
        pHead.next = head
        pre = head
        cur = head.next
        while cur:
            pre.next = cur.next
            cur.next = pHead.next
            pHead.next = cur
            cur = pre.next
        return pHead.next

练习:92 83 86 328 2 445

203. 移除链表元素

# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution(object):
    def removeElements(self, head, val):
        pHead = ListNode(0)
        pHead.next = head
        left = pHead
        right = pHead.next
        while right:
            if right.val == val:
                left.next = right.next
                right = left.next
            else:
                left = left.next
                right = right.next
        return pHead.next

练习:82 21

24. 两两交换链表中的节点

# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None

# 使用虚拟头结点
class Solution(object):
    def swapPairs(self, head):
        pHead = ListNode(0)
        pHead.next = head
        
        p = pHead
        while p.next and p.next.next: # 保证要交换的两个节点存在
            node1 = p.next
            node2 = node1.next
            
            node1.next = node2.next
            node2.next = node1
            p.next = node2
            
            p = node1  # 对p进行更新 准备进入下一次循环
        return pHead.next

 

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

# 递归法
class Solution:
    def swapPairs(self, head: ListNode) -> ListNode:
        if not head or not head.next:
            return head          # 递归退出条件
        # 对两个节点进行交换
        cur = head.next
        head.next = cur.next
        cur.next = head
        # 对剩余节点进行递归交换
        head.next = self.swapPairs(head.next)
        return cur               # 交换后第一个节点为cur 

练习:25 147 148

237. 删除链表中的节点

# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution(object):
    def deleteNode(self, node):
        node.val = node.next.val     # 用下一个节点的值将当前节点值覆盖
        node.next = node.next.next   # 用一个节点的指针将当前节点的指针覆盖

19. 删除链表的倒数第N个节点

# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution(object):
    def removeNthFromEnd(self, head, n):
        if not head:
            return []
        pHead = ListNode(0)
        pHead.next = head
        pre = pHead
        left = pHead.next
        right = pHead.next
        for _ in range(n):
            right = right.next
        while right:
            right = right.next
            left = left.next
            pre = pre.next
        pre.next = left.next
        return pHead.next       

练习:61 143 234

20. 有效的括号

class Solution:
    def isValid(self, s: str) -> bool:
        dic = {'(':')', '[':']','{':'}'}
        stack = []
        for char in s:
            if char in dic:
                stack.append(char)
            elif not stack or dic[stack.pop()] != char:
                return False         
        return len(stack) == 0

 

class Solution:
    def isValid(self, s: str) -> bool:
        if not s:
            return True
        if len(s) % 2 != 0:
            return False
        dic = {'(':')', '[':']','{':'}'}
        stack = []
        for char in s:
            if char in dic:
                stack.append(char)
            elif stack:
                tmp = stack.pop()
                if dic[tmp] == char:
                    continue
                else:
                    return False
            else:
                return False
        return len(stack) == 0

练习:150 71

144. 二叉树的前序遍历

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
# 非递归实现
class Solution:
    def preorderTraversal(self, root: TreeNode) -> List[int]:
        if not root:
            return []
        stack = [root]
        result = []
        while stack:
            node = stack.pop()
            result.append(node.val)
         # 因为要先遍历左子树 所以要先将右子树入栈 先进后出!   
            if node.right:              
                stack.append(node.right) 
            if node.left:
                stack.append(node.left)     
        return result

94. 二叉树的中序遍历

class Solution:
    def __init__(self):
        self.res = []
    def inorderTraversal(self, root: TreeNode) -> List[int]:
        if not root:
            return []
        stack = []
        while stack or root:
            while root:
                stack.append(root)
                root = root.left
            root = stack.pop()
            self.res.append(root.val)
            root = root.right
        return self.res

 

145. 二叉树的后序遍历

class Solution:
    def __init__(self):
        self.res = []
    def postorderTraversal(self, root: TreeNode) -> List[int]:
        if not root:
            return []
        stack1 = [root]
        stack2 = []
        while stack1:
            node = stack1.pop()
            stack2.append(node.val)
            if node.left:
                stack1.append(node.left)
            if node.right:
                stack1.append(node.right)
        while stack2:
            self.res.append(stack2.pop())
        return self.res

 

练习:341

102. 二叉树的层次遍历

class Solution:
    def levelOrder(self, root: TreeNode) -> List[List[int]]:
        if not root:
            return []
        queue = [root]
        res = []
        while queue:
            k = len(queue)
            tmp = []
            for _ in range(k):
                node = queue.pop(0)
                tmp.append(node.val)
                if node.left:
                    queue.append(node.left)
                if node.right:
                    queue.append(node.right)
            res.append(tmp)
        return res

练习:107 103 199 346

279

练习:127 126 286

347

练习:23

104. 二叉树的最大深度

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def maxDepth(self, root):
        if not root:
            return 0
        return max(self.maxDepth(root.left), self.maxDepth(root.right))+1

111. 二叉树的最小深度

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

# 路径的最后一个节点必须是叶子节点
class Solution:
    def minDepth(self, root: TreeNode) -> int:
        if not root: 
            return 0
        if not root.left:             # 对根节点没有左子树的情况进行判断
            return self.minDepth(root.right) + 1
        if not root.right:            # 对根节点没有右子树的情况进行判断
            return self.minDepth(root.left) + 1
        return min(self.minDepth(root.left), self.minDepth(root.right)) + 1 # 根节点同时有左右子树

 

226. 翻转二叉树

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def invertTree(self, root: TreeNode) -> TreeNode:
        if not root:
            return 
        self.invertTree(root.left)
        self.invertTree(root.right)
        tmp = root.left
        root.left = root.right
        root.right = tmp
        return root

练习:100 101 222 110

112. 路径总和

class Solution:
    def hasPathSum(self, root: TreeNode, sum: int) -> bool:
        if not root:        # 当前节点为空,则退出递归
            return False
        if not root.left and not root.right: # 当前结点不为空,且为叶子节点
            return sum == root.val           # 判断叶子节点是否等于剩余数字
        return self.hasPathSum(root.left, sum - root.val) or \
               self.hasPathSum(root.right, sum - root.val)
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def __init__(self):
        self.sum = 0
        self.res = []
    def hasPathSum(self, root: TreeNode, sum: int) -> bool:
        if not root:
            return False
        self.sum += root.val
        if not root.left and not root.right and self.sum == sum:
            self.res.append(1)            # 如果有满足条件的路径则添加一个记录
        self.hasPathSum(root.left, sum)
        self.hasPathSum(root.right, sum)
        self.sum -= root.val              # 如果不满足条件则减去改值 
        return len(self.res) != 0

练习:111 404

257. 二叉树的所有路径

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def find_paths(self, root, res, path):
        if not root:                          # 递归出口
            return
        path += str(root.val)
        if not root.left and not root.right:  # 当前节点是叶子节点
            res.append(path)                  # 把路径加入到答案中
            return
        path += '->'            # 当前节点不是叶子节点,继续递归遍历
        self.find_paths(root.left, res, path)
        self.find_paths(root.right, res, path)
    
    def binaryTreePaths(self, root: TreeNode) -> List[str]:
        res = []
        path = ''
        self.find_paths(root, res, path)
        return res   

练习:113 129 222

113. 路径总和 II

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def __init__(self):
        self.path = []
        self.res = []
        self.sum = 0
    def pathSum(self, root: TreeNode, sum: int) -> List[List[int]]:
        if not root:
            return 
        
        self.sum += root.val
        self.path.append(root.val)
        if not root.left and not root.right and self.sum == sum:
            self.res.append(self.path[:])
        self.pathSum(root.left, sum)
        self.pathSum(root.right, sum)
        
        self.sum -= root.val
        self.path.pop()
        return self.res  

437. 路径总和 III

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def findPath(self, root, num):
        if not root:
            return 0

        count = 0          # 每进入一次递归就要记录可能满足条件的路径个数
        if root.val == num:
            count += 1     # 如果当前结点值满足条件
        # 如满足if条件,判断子树之和是否有0的情况;若不满足if,判断是否子树之和 加 root.val等于num
        count += self.findPath(root.left, num - root.val) 
        count += self.findPath(root.right, num - root.val)
        return count
    
    def pathSum(self, root: TreeNode, sum: int) -> int:
        if not root:
            return 0
        # 和为sum 共有两种情况 包含跟结点与不包含根节点
        return self.findPath(root, sum) + self.pathSum(root.left, sum) \
               + self.pathSum(root.right, sum)  # 注意此时不是sum - root.val

783. 二叉搜索树结点最小距离

'''
直观的思路是先将二叉树进行中序遍历并将结果放入数组中,然后对数组进行遍历,时间空间复杂度均为O(n)。
其实可以不用存储中序遍历的结果,而是用一个变量pre来储存中序遍历上一个节点的值,空间复杂度降低到O(1)。
'''
class Solution:
    def in_order(self, node):
        if not node:
            return 
        self.in_order(node.left)
        self.res = min(self.res, node.val - self.pre)
        self.pre = node.val
        self.in_order(node.right)
            
    def minDiffInBST(self, root: TreeNode) -> int:    
        self.pre = float('-inf')
        self.res = float('inf')
        self.in_order(root)
        return self.res
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def minDiffInBST(self, root: TreeNode) -> int:
        if not root:
            return
        nums = []
        def in_order(root):
            if not root:
                return
            in_order(root.left)
            nums.append(root.val)
            in_order(root.right)
            
        in_order(root)
        n = len(nums)
        minNum = float('inf')
        for i in range(n-1):
            minNum = min(minNum, nums[i+1]-nums[i])
        return minNum

235. 二叉搜索树的最近公共祖先

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
# 共有五种情况 pq同在根节点两侧 pq分别在根节点两侧 或pq其中有一个为祖先
class Solution:
    def lowestCommonAncestor(self, root, p, q):
        if not root:
            return
        if p.val < root.val and q.val < root.val:           # pq同在根节点左侧 公共祖先肯定在左子树上
            return self.lowestCommonAncestor(root.left, p, q) # 在左子树上寻找
        if p.val > root.val and q.val > root.val:           # pq同在根节点右侧 公共祖先肯定在右子树上
            return self.lowestCommonAncestor(root.right, p, q)# 在右子树上寻找
        return root                                         # 其他三种情况 当前结点即为最近公共祖先
        

练习:98 450 108 230 236 530

17. 电话号码的字母组合

Leetcode题解------Python语言实现_第1张图片

class Solution:
    def letterCombinations(self, digits):
        lookup = {
            '2':['a','b','c'], '3':['d','e','f'], '4':['g','h','i'], '5':['j','k','l'],
            '6':['m','n','o'], '7':['p','q','r','s'], '8':['t','u','v'], '9':['w','x','y','z']
        }
        
        def helper(digits, s):
            if not digits:
                res.append(s)
                return
            cur_digit = digits[0]  # 第一个即为当前要遍历的数字
            # 将当前数字代表的字母依次加入到s中, 然后再对下一个数字进行处理
            for char in lookup[cur_digit]:  # 取出当前数字对应的字符 并对其进行遍历
                helper(digits[1:], s+char)  
                
        if not digits:
            return []
        res = []
        helper(digits, '')
        return res

练习:93 131

46. 全排列

Leetcode题解------Python语言实现_第2张图片

class Solution:
    def permute(self, nums):    
        if not nums:
            return []
        n = len(nums)
        if n == 1:
            return [nums]
        res = []
        for i in range(n): # 逐渐缩小问题规模
            tmp = self.permute(nums[:i]+nums[i+1:])
            for j in tmp:
                res.append([nums[i]]+j)
        return res
class Solution:
    def permute(self, nums):
        
        def helper(nums, index, p):
            if index == len(nums):     # 当达到指定个数时
                res.append(p[:])
                return
            for i in range(len(nums)): # 对每一个数字进行遍历
                if not used[i]:        # 如果当前数字并未被使用
                    used[i] = 1        # 标记已经使用
                    p.append(nums[i])  # 使用
                    helper(nums, index + 1, p) # 对剩余数字进行判断
                    p.pop()            # 使用完成后要对当前数字进行释放 并将标记置为未使用
                    used[i] = 0        # 状态回溯
        
        if not nums:
            return []
        res = []
        used = [0 for i in range(len(nums))] # 用于记录当前索引的数字是否已经使用
        helper(nums, 0, []) # 传入要全排列的列表,起始位置,暂存全排列的列表
        return res

练习:47

77. 组合

Leetcode题解------Python语言实现_第3张图片

class Solution:
    def combine(self, n, k):
        
        def helper(start, p):       # 从当前索引往后的范围内取数并加入到p中
            if len(p) == k:         # 如果已经达到个数 则将其加入到结果列表中
                res.append(p[:])
                return
            # [i...n] 中至少要有k-len(cur)个元素i最多为n-(k-len(cur))+1
            for i in range(start, n-(k-len(cur))+ 2):  # 剪枝操作
                p.append(i)         # 当前数字
                helper(i+1, p)      # 将当前数字排除 并递归地从中取数
                p.pop()             # 将p加入res中后 要逐层将其释放
                
        if n < 1 or k < 1 or k > n:
            return []
        res = []
        helper(1, [])
        return res

练习:39 40 216 78 90 401

79

class Solution:
    def exist(self, board, word):
        if not board:
            return False
        m = len(board)             # 行数 
        n = len(board[0])          # 列数
        directions = [(0, -1), (-1, 0), (0, 1), (1, 0)]
        visited = [[False for _ in range(n)] for _ in range(m)] # 用于记录的矩阵
        
        def searchWord(index, i, j):
            if index == len(word) - 1: # 递归终止条件
                return board[i][j] == word[index] # 判断最后一个元素与矩阵中元素是否相等
            if board[i][j] == word[index]: # 当前元素匹配之后 再去匹配下一个
                visited[i][j] = True       # 对标记进行更新
                for d in directions:
                    new_i = i + d[0]
                    new_j = j + d[1]
                    # 确保更新之后的xy在矩阵范围内,并且该元素并未被使用过
                    if 0 <= new_i < m and 0 <= new_j < n and not visited[new_i][new_j] and \
                            searchWord(index + 1, new_i, new_j):
                        return True  # 注意:如果这一次 search word 成功的话,就返回
                visited[i][j] = False  # 将对应位置做出标记
            return False
        
        for i in range(m):
            for j in range(n):     # 遍历每一个元素
                if searchWord(0, i, j):
                    return True    # 找到返回 True
        return False               # 没有找到 False  

200. 岛屿数量

class Solution:
    def numIslands(self, grid: List[List[str]]) -> int:
        m = len(grid)
        if m == 0:
            return 0
        n = len(grid[0])
        res = 0
        directions = [[0, 1], [0, -1], [1, 0], [-1, 0]]
        visited = [[False for _ in range(n)] for _ in range(m)]
        
        def dfs(i,j):
            visited[i][j] = True
            for d in directions:
                new_i = i + d[0]
                new_j = j + d[1]
                if 0 <= new_i < m and 0 <= new_j < n and not visited[new_i][new_j] and                              grid[new_i][new_j] == '1':
                    dfs(new_i, new_j)
        
        for i in range(m):
            for j in range(n):
                if not visited[i][j] and grid[i][j] == '1':
                    res += 1
                    dfs(i, j)
        return res  

练习:130 417

51

练习:52 37

70. 爬楼梯

class Solution:
    def climbStairs(self, n):
        if n <= 3:
            return n
        res = [2, 3]
        for _ in range(n-3):
            res.append(res[-1] + res[-2])
        return res[-1]

练习:120 64

343

练习:279 91 62 63

198

练习:213 337 309

416

练习:322 377 474 139 494

300

练习:376

455

练习:392

435

 

62. 不同路径

思路一:动态规划

# 时间复杂度:O(m*n)
# 空间复杂度:O(m*n)
class Solution:
    def uniquePaths(self, m: int, n: int) -> int:
        dp = [[1 for _ in range(n)] for _ in range(m)] #第一行或者第一列都是在边界,只能为 1
        for i in range(1, m):
            for j in range(1, n):
                dp[i][j] = dp[i-1][j] + dp[i][j-1] #dp[i][j]是到达i,j最多路径,dp[i][j]=dp[i-1][j]+dp[i][j-1]
        return dp[-1][-1]

优化:

class Solution:
# 因为每次只需要 dp[i-1][j],dp[i][j-1] 所以我们只要记录这两个数
    def uniquePaths(self, m: int, n: int) -> int:
        dp = [1]*n
        for i in range(1, m):
            for j in range(1, n):
                dp[j] += dp[j-1]
        return dp[-1]

思路二:排列组合

机器人一定会走m+n-2步,即从m+n-2中挑出m-1步向下走就行了,即

63. 不同路径 II

class Solution:
    def uniquePathsWithObstacles(self, obstacleGrid):
        if not obstacleGrid or not obstacleGrid[0]:
            return 0
        m, n = len(obstacleGrid), len(obstacleGrid[0])
        dp = [1] + [0]*n               # 先假设有一条路径
        for i in range(m):             # 走每一个网格
            for j in range(n):
                if obstacleGrid[i][j]: # 如果存在障碍物
                    dp[j] = 0          # 当前路径不可通过
                else:                  # 如果不存在障碍物
                    dp[j] = dp[j]+dp[j-1] # 当前路径加上另一个方向的路径和
        return dp[-2]

64. 最小路径和

class Solution:
    def minPathSum(self, grid):
        if not grid or not grid[0]:
            return 0
        m, n = len(grid), len(grid[0])
        dp = [0]*n
        dp[0] = grid[0][0]
        for i in range(1,n):
            dp[i] = dp[i-1] + grid[0][i]

        for i in range(1,m):
            dp[0] = grid[i][0] + dp[0]
            for j in range(1,n):
                dp[j]= min(dp[j],dp[j-1]) + grid[i][j]
        return dp[-1]

 

153. 寻找旋转排序数组中的最小值

 


1 two sum
对于stack和queue,除了pop外,查找的时间复杂度是O(n)。hash map, 查找的时间复杂度理想情况下是O(1)。所以先来考虑
hash map来求解这个问题。python中的字典dictionary在查找key时使用的是hashmap的方式,查找速度较快

class Solution(object):
    def twoSum(self, nums, target):
        lookup = {}        # 定义新的缓冲区,可以得到“空间换时间”的效果,降低时间复杂度
        for i, num in enumerate(nums):  # 遍历一次,时间复杂度O(n)
            if target - num in lookup:  # hashmap查找,时间复杂度O(1)
                return [lookup[target - num], i] # 若查找成功直接返回索引
            else:
                lookup[num] = i         # 查找失败,以数字为键索引为值添加的字典中

7 Reverse Integer
Python采用切片实现逆序非常简单,但是切片的对象可以是字符串、列表、元组,没有整数。
因此要对整数实现逆序,首先就要把整数变成字符串,逆序后再由字符串变成整数。

class Solution(object):
    def reverse(self, x):
        if x < 0:       # 处理负数时,现将负数变成正数,逆序后再乘以负一
            y = -1 * int(str(-x)[::-1])
        else:
            y = int(str(x)[::-1])
        return y if -2**-31 <= y <= 2**31-1 else 0


9 Palindrome Number

class Solution:
    def isPalindrome(self, x):
        if x < 0:
        	return False
        elif x != int(str(x)[::-1])
        	return False
        else:
        	return True

21. 合并两个有序链表

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:
        p1, p2 = l1, l2
        head = ListNode(0)
        cur = head
        while p1 and p2:
            if p1.val <= p2.val:
                cur.next = p1
                cur = cur.next
                p1 = p1.next
            else:
                cur.next = p2
                cur = cur.next
                p2 = p2.next
        if p1:
            cur.next = p1
        if p2:
            cur.next = p2
        return head.next

23. 合并K个排序链表

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

# 与归并排序思路一样,先对n个待排序的链表进行拆分,然后再两两进行排序
class Solution:
    def mergeKLists(self, lists: List[ListNode]) -> ListNode:
        def merge(list1, list2):
            head = ListNode(0)
            cur = head
            while list1 and list2:
                if list1.val < list2.val:
                    cur.next = list1
                    list1 = list1.next
                    cur = cur.next
                else:
                    cur.next = list2
                    list2 = list2.next
                    cur = cur.next
            if list1:
                cur.next = list1
            if list2:
                cur.next = list2
            return head.next
        
        if not lists:
            return
        n = len(lists)
        if n == 1:
            return lists[0]
        mid = n//2
        list1 = self.mergeKLists(lists[:mid])
        list2 = self.mergeKLists(lists[mid:])
        return merge(list1, list2)

98. 验证二叉搜索树

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution(object):
    def isValidBST(self, root):
        def inOrder(root):
            if not root:
                return
            inOrder(root.left)
            res.append(root.val)
            inOrder(root.right)
            
        res = []   
        inOrder(root)
        for i in range(len(res)-1):
            if res[i] >= res[i+1]:
                return False
        return True        

101. 对称二叉树

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def is_mirror(self, left, right):
        if not left and not right:
            return True
        if not left or not right:
            return False
        if left.val == right.val:
            return self.is_mirror(left.left, right.right) and self.is_mirror(left.right, right.left)
    
    def isSymmetric(self, root: TreeNode) -> bool:
        if not root:
            return True
        return self.is_mirror(root.left, root.right)

103. 二叉树的锯齿形层次遍历

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def zigzagLevelOrder(self, root: TreeNode) -> List[List[int]]:
        if not root:
            return []
        queue = [root]
        res = []
        k = 0
        while queue:
            n = len(queue)
            tmp = []
            k += 1
            for _ in range(n):
                node = queue.pop(0)
                tmp.append(node.val)
                if node.left:
                    queue.append(node.left)
                if node.right:
                    queue.append(node.right)
            if k % 2 == 1:
                res.append(tmp)
            else:
                res.append(tmp[::-1])
        return res        

108. 将有序数组转换为二叉搜索树 

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def sortedArrayToBST(self, nums: List[int]) -> TreeNode:
        if not nums:
            return
        mid = len(nums) // 2
        node = TreeNode(nums[mid])
        node.left = self.sortedArrayToBST(nums[:mid])
        node.right = self.sortedArrayToBST(nums[mid+1:])
        return node

110. 平衡二叉树

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def get_depth(self, root):      # 从下往上遍历,减少每个结点需要遍历的次数
        if not root:
            return 0
        left = self.get_depth(root.left) # 要么返回-1表示不是平衡二叉树,要么返回树的深度
        if left == -1:              # 若左子树不是平衡二叉树
            return -1
        right = self.get_depth(root.right)
        if right == -1:             # 若右子树不是平衡二叉树
            return -1
        if abs(left - right) > 1:   # 从下往上判断当前子树是否为平衡二叉树
            return -1               # 若不是 直接返回-1
        return max(left, right) + 1 # 若是平衡二叉树 返回当前子树的深度
        
    def isBalanced(self, root: TreeNode) -> bool:
        return self.get_depth(root) != -1

138. 复制带随机指针的链表

"""
# Definition for a Node.
class Node:
    def __init__(self, val, next, random):
        self.val = val
        self.next = next
        self.random = random
"""
class Solution:
    def copyRandomList(self, head: 'Node') -> 'Node':
        if not head:
            return
        # 第一步:复制链表
        cur = head
        while cur:
            node = Node(cur.val, None, None)
            node.next = cur.next
            cur.next = node
            cur = node.next
        # 第二步:复制随机指针
        cur = head
        while cur:
            if cur.random:
                cur.next.random = cur.random.next
            cur = cur.next.next
        # 第三步:链表拆分
        cur = head
        pHead = head.next
        pCur = pHead
        while cur:
            cur.next = cur.next.next
            if pCur.next:
                pCur.next = pCur.next.next
            cur = cur.next
            pCur = pCur.next
        return pHead

141. 环形链表

# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution(object):
    def hasCycle(self, head):
        if not head:
            return False
        slow = head
        fast = head
        while fast and fast.next:
            slow = slow.next
            fast = fast.next.next
            if slow == fast:
                return True
        return False

142. 环形链表 II

# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution(object):
    def detectCycle(self, head):
        def find_loop(head):
            if not head:
                return
            slow = head
            fast = head
            while fast and fast.next:
                slow = slow.next
                fast = fast.next.next
                if slow == fast:
                    return slow
            return
        
        end = find_loop(head)
        if not head or not end:
            return
        begin = head
        while begin != end:
            begin = begin.next
            end = end.next
        return end        

155. 最小栈

class MinStack(object):
    def __init__(self):
        self.stack1 = []
        self.stack2 = []  
        
    def push(self, x):
        self.stack1.append(x)
        if not self.stack2 or x <= self.stack2[-1]:
            self.stack2.append(x)

    def pop(self):  
        if self.stack1[-1] == self.stack2[-1]:
            self.stack2.pop()
        self.stack1.pop()

    def top(self):
        return self.stack1[-1]        

    def getMin(self):
        if self.stack2:
            return self.stack2[-1]
        return        

160. 相交链表

# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution(object):
    def getIntersectionNode(self, headA, headB):
        if not headA or not headB:
            return
        p, q = headA, headB
        len1, len2 = 0, 0
        while p:
            len1 += 1
            p = p.next
        while q:
            len2 += 1
            q = q.next
        if len1 > len2:
            p, q = headA, headB
        else:
            p, q = headB, headA
        for _ in range(abs(len1 - len2)):
            p = p.next
        while p != q:
            p = p.next
            q = q.next
        return p

215. 数组中的第K个最大元素

class Solution:
    def findKthLargest(self, nums: List[int], k: int) -> int:
        def adjust_heap(nums, i, n):
            left = 2*i + 1
            right = 2*i + 2
            maxS = i
            if i <= n//2:
                if left < n and nums[left] > nums[maxS]:
                    maxS = left
                if right < n and nums[right] > nums[maxS]:
                    maxS = right
                if maxS != i:
                    nums[i], nums[maxS] = nums[maxS], nums[i]
                    adjust_heap(nums, maxS, n)
        
        def build_heap(nums, n):
            for i in range(n//2)[::-1]:
                adjust_heap(nums, i, n)
        
        n = len(nums)
        build_heap(nums, n)
        for i in range(n)[::-1]:    # 逐个将堆顶元素放到有序数组中
            nums[0], nums[i] = nums[i], nums[0]
            adjust_heap(nums, 0, i)
        print(nums)
        return nums[-k]

230. 二叉搜索树中第K小的元素

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def __init__(self):
        self.m = 0
        self.res = []
    def kthSmallest(self, root: TreeNode, k: int) -> int:
        if not root:
            return
        self.kthSmallest(root.left, k)
        self.m += 1
        if self.m == k:
            self.res.append(root.val)
        self.kthSmallest(root.right, k)
        if self.res:
            return self.res[0]

263. 丑数 

class Solution:
    def isUgly(self, num: int) -> bool:
        if num <= 0:
            return False
        if num == 1:
            return True
        while num > 1:
            if num % 2 == 0:    # 除2余0 即能被2整除
                num /= 2
            elif num % 3 == 0:  # 能被3整除
                num /= 3
            elif num % 5 == 0:  # 能被5整除
                num /= 5
            else:
                return False    # 不能被235整除则不是丑数
        return True             # num最后为1时 该数为丑数

264. 丑数 II

class Solution:
    def nthUglyNumber(self, n: int) -> int:
        if n <= 1:
            return n 
        res = [1] * n
        i2, i3, i5 = 0, 0, 0   # 所有丑数肯定是之前的数字乘 235 得到的
        for i in range(1, n):
            num2 = res[i2] * 2 # 模拟之前丑数乘2得到的队列
            num3 = res[i3] * 3 # 模拟乘3得到的队列
            num5 = res[i5] * 5 # 模拟乘5得到的队列
            res[i] = min(num2,min(num3, num5)) # 在三个队列中取出一个最小的放入当前位置
            if res[i] == num2:
                i2 += 1        # 模拟出队
            if res[i] == num3:
                i3 += 1
            if res[i] == num5:
                i5 += 1
        return res[-1]

347. 前 K 个高频元素

class Solution:
    def topKFrequent(self, nums: List[int], k: int) -> List[int]:
        if not nums or k < 1:
            return []
        dic = dict()
        res = []
        for num in nums:
            if num not in dic:
                dic[num] = 1
            else:
                dic[num] += 1
        items = list(dic.items())
        items.sort(key = lambda x: -x[1])
        res = [tmp[0] for tmp in items]
        return res[:k]

449. 序列化和反序列化二叉搜索树

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Codec:
    def serialize(self, root):
        def pre_order(root):
            if not root:
                res.append("#")
                return
            res.append(str(root.val))
            pre_order(root.left)
            pre_order(root.right)
            
        res = []
        pre_order(root)
        return ' '.join(res)
        
    def deserialize(self, data):
        nums = iter(data.split())
        def pre_order():
            num = next(nums)
            if num =="#":
                return
            node = TreeNode(int(num))
            node.left = pre_order()
            node.right = pre_order()
            return node
        return pre_order()

572. 另一个树的子树

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def isSub(self, a, b):
        if a == b:
            return True
        if a and b and a.val == b.val:
            return self.isSub(a.left, b.left) and self.isSub(a.right, b.right)
        else:
            return False
    
    def isSubtree(self, s: TreeNode, t: TreeNode) -> bool:
        if not s or not t:
            return False
        return self.isSub(s, t) or self.isSubtree(s.left, t) or self.isSubtree(s.right, t)

704. 二分查找

class Solution:
    def search(self, nums: List[int], target: int) -> int:
        if not nums:
            return -1
        n = len(nums)
        left = 0
        right = n-1
        while left <= right:
            mid = (left + right) // 2
            if nums[mid] == target:
                return mid
            elif nums[mid] > target:
                right = mid-1
            else:
                left = mid + 1
        return -1

852. 山脉数组的峰顶索引

class Solution:
    def peakIndexInMountainArray(self, A: List[int]) -> int:
        if not A:
            return 
        n = len(A)
        left = 0
        right = n - 1
        while left <= right:
            mid = (left + right)//2
            if A[mid] > A[mid+1] and A[mid] > A[mid-1]:
                return mid
            elif A[mid] > A[mid+1]:
                right = mid
            else:
                left = mid

 

你可能感兴趣的:(数据结构与算法)