Code算法

目录

  • 1. 题记
  • 2. 题型分类
    • 滑动窗
    • 递归分治
      • 回溯:
      • 剪枝:
    • 动态规划DP⭐ (dynamic planning)
        • 背包问题:
    • 树的算法
      • 1. 广度优先搜索BFS
      • 2. 深度优先搜索DFS
      • 3. 二叉搜索树BST
      • 4.前缀树(字典树)Trie
    • 字符串匹配KMP
    • 位运算
    • 二分法
    • 状态压缩
  • 3. 题目列表
    • 剑指offer:
        • Offer 06.从头到尾打印链表
        • Offer 08.双栈实现队列
        • Offer 10-1斐波那契数列
        • Offer10-2.青蛙跳台阶问题
        • Offer 11.旋转数组的最小数字
        • Offer 15.二进制中1的个数
        • Offer 18.删除链表节点
        • Offer 21. 调整数组顺序使奇数位于偶数前面
        • Offer 22.链表中倒数第k个节点
        • Offer 24.反转链表
        • Offer 29. 顺时针打印矩阵
        • Offer30.包含min函数的栈
        • Offer32-II.从上到下打印二叉树II
        • Offer39.数组中出现次数超过一半的数字
        • Offer42.连续子数组的最大和
        • Offer50.第一个只出现一次的字符
        • Offer52.两个链表的第一个公共节点
        • Offer53-Ⅰ
        • Offer54.二叉搜索树的第k大节点
        • Offer55-I.二叉树的深度
        • Offer55-Ⅱ.平衡二叉树
        • Offer57.和为s的两个数字
        • Offer58-I.翻转单词顺序
        • Offer58-Ⅱ.左旋转字符串
        • Offer61.扑克牌中的顺子
        • Offer62.圆圈中最后剩下的数字
        • Offer65.不用加减乘除做加法
    • 14. 最长公共前缀
    • 220.存在重复元素III❓
    • 1143.最长公共子序列
    • 3.无重复字符的最长子串 ⭐⭐⭐
      • 暴力搜索:
      • 滑动窗口:❓
    • 28.实现strStr()
    • 面试题56-I.数组中数字出现的次数
    • 137.只出现一次的数字Ⅱ
      • 位运算
      • 状态机❓
    • 554.砖墙
    • 7.整数反转
    • 1473.粉刷房子Ⅲ
    • 198.打家劫舍
    • 740.删除并获得点数
    • 1720.解码异或后的数组
    • 1486.数组异或操作
    • 1723.完成所有工作的最短时间❓
      • 1. 动态规划+状态压缩
    • 1482.制作m束花所需的最少天数
    • 872.叶子相似的树
    • 1734.解码异或后的排列
    • 1310.子数组异或查询
    • 1269.停在原地的方案数
    • 12.整数转罗马数字
    • 13.罗马数字转整数
    • 208.实现Trie(前缀树)
    • 421.数组中两个数的最大异或值
    • 421.数组中两个数的最大异或值
    • 993.二叉树的堂兄弟节点
    • 1442.形成两个异或相等数组的三元组数目
    • 692.前k个高频单词
    • 1035.不相交的线
    • 1707.与数组中元素的最大异或值
    • 131.分割回文串
    • 664.奇怪的打印机
    • 1190.反转每队括号间的子串
    • 477.汉明距离总和
    • 234.2的幂
    • 342.4的幂
    • 523.连续的子数组和
    • 525.连续数组
    • 160.相交链表
    • 474.一和零
    • 494.目标和
    • 879.盈利计划
    • 518.零钱兑换
    • 279.完全平方数
    • 877.石子游戏
    • 401.二进制手表
    • 38.字符串的排序
    • 149.直线上最多的点数
    • 168.Excel表列名称
    • LCP07.传递信息
    • 1833.雪糕的最大数量
    • 726.原子的数量
    • 1711.大餐计数
    • 930.和相同的二元子数组
    • 981.基于时间的键值存储
    • 274.H的指数
    • 275.H指数Ⅱ
    • 218.天际线问题⭐⭐
    • 1818.绝对差值和
    • 1931.用三种不同颜色为网格涂色⭐❓
    • 面试题10.02.变位词组
    • 1838.最高频元素的频数
    • 138.复制带随机指针的链表
    • 1738.找出第K大的异或坐标值
    • 671.二叉树中第二小的节点
    • 987.二叉树的垂序遍历
    • 611.有效三角形个数
    • 847.访问所有节点的最短路径
    • 516.最长回归子序列
    • 470.用Rand7()实现Rand10()
    • 318.最大单词长度乘积
  • python

1. 题记

本篇博客旨在便于作者本人学习记录,方便翻阅。故所引用之处皆已附上链接。能力有限,也望能给诸位带来些许方便。语言:python

2. 题型分类


滑动窗

  • 220.存在重复元素III
  • 3.无重复字符的最长子串

递归分治

程序调用自身

回溯:

用递归实现的算法。递归调用之前「做选择」,在递归调用之后「撤销选择」。

剪枝:

搜索算法:暴力搜索 ⟹ \Longrightarrow 剪枝+优化。参考在(☞゚ヮ゚)☞这里


动态规划DP⭐ (dynamic planning)

最常见

  • 1143.最长公共子序列
  • 1473.粉刷房子Ⅲ
  • 198.打家劫舍
  • 740. 删除并获得点数
  • 1269.停在原地的方案数
  • 1035.不相交的线
  • 518.零钱兑换
  • 279.完全平方数
  • 877.石子游戏

重叠子问题、最优子结构、状态转移方程:动态规划三要素

  1. 找状态转移方程:eg. f ( n ) = f ( n − 2 ) + a f(n) = f(n-2)+a f(n)=f(n2)+a
  2. 自底向上计算,重用子问题的解:使用dp表或者备忘录,将解存起来复用。
    dp表从一维到三维不等
背包问题:

01背包:总容量有限,如何装使得背包价值最大。物体:(体积、价值)。
dp[i][capacity] = value


树的算法

  • 144.二叉树的前序遍历
  • 145.二叉树的后序遍历
  • 993.二叉树的堂兄弟节点
  • 872.叶子相似的树
  • 671.二叉树中第二小的节点

1. 广度优先搜索BFS

迭代法:队列

def BFS(root):
	queue = [root]
	while queue:
		p = queue.pop(0)
		if p.left:
			queue.append(p.left)
		if p.right:
			queue.append(p.right)

2. 深度优先搜索DFS

迭代法:栈

def DFS(root):
    p = root
    stack = [p]
    while p.left:
        p = p.left
        stack.append(p) # 左子树入栈

    while stack:
    # 栈顶元素出栈,将其右节点入栈,并重复将该将右节点的所有左节点入栈
        p = stack.pop()
        if p.right:
            p = p.right
            stack.append(p) # 栈顶元素右节点入栈
            while p.left: # 并将该节点所有左子树节点入栈
                p = p.left
                stack.append(p)
    return leaf

递归法:重复自身(一般递归效率低)

def DFS(root):
	if root is None:
		return
	# root.val # 前序
	DFS(root.left)
	# root.val # 中序
	DFS(root.right)
	# root.val # 后序

3. 二叉搜索树BST

每个节点的值大于其左侧子节点的值,小于右节点的值。

4.前缀树(字典树)Trie

  • 208.实现Trie(前缀树)
  • 421.数组中两个数的最大异或值


字符串匹配KMP

  • 28.实现strStr()

位运算

  • 面试题56-I.数组中数字出现的次数
  • 137.只出现一次的数字Ⅱ
  • 1720.解码异或后的数组
  • 1486.数组异或操作
  • 1734.解码异或后的排列
  • 1310.子数组异或查询
  • 421.数组中两个数的最大异或值
  • 1442. 形成两个异或相等数组的三元组数目
  • 477.汉明距离总和
  • 234. 2的幂; 342. 4的幂

bin()转二进制
0x:16进制,0b:2进制

python是无?符号二进制

& | ^ ~ << >>
异或XOR ‘⊕’ 取反 左移 右移
1&1为1,其余为0 0|0为0,其余为1 相同为0相异为1

异或运算规律:转自☞这里

  1. x ⊕ x = 0 x \oplus x = 0 xx=0
  2. x ⊕ y = y ⊕ x x \oplus y = y \oplus x xy=yx(交换律);
  3. ( x ⊕ y ) ⊕ z = x ⊕ ( y ⊕ z ) (x \oplus y) \oplus z = x \oplus (y \oplus z) (xy)z=x(yz)(结合律);
  4. x ⊕ y ⊕ y = x x \oplus y \oplus y = x xyy=x(自反性);
  5. ∀ i ∈ Z \forall i \in Z iZ,有 4 i ⊕ ( 4 i + 1 ) ⊕ ( 4 i + 2 ) ⊕ ( 4 i + 3 ) = 0 4i \oplus (4i+1) \oplus (4i+2) \oplus (4i+3) = 0 4i(4i+1)(4i+2)(4i+3)=0

二分法

1482.制作 m 束花所需的最少天数
981.基于时间的键值存储

找最优值

def binaryFind(data, target):
	left, right = min, max (都能取到)
	mid = (left + right) // 2
	while left <= right:
		if is_satisfy(mid,data):
			return data[mid]
		elif over_satisfy(mid,data):
			right = mid - 1
		else:
			left = mid + 1	
	return left or right

运用到查找最优值时:第一个不小于目标值的数,或者查找最后一个小于目标值的数。
while left <= right:
最后:left:大于等于目标值的最小值,right:小于等于目标值的最大值。
变形:❓

状态压缩

e.g. 用n位二进制表示n位0-1状态。
取第i位状态:(num >> i) & 1
改第i位状态为1num = num | (1 << i)s


3. 题目列表

剑指offer:

Offer 06.从头到尾打印链表
# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def reversePrint(self, head: ListNode) -> List[int]:
        # 从尾到头反过来返回每个节点的值
        # 方法1:list存储节点值,最后list翻转
        result = [] 
        p = head
        while p:
            result.append(p.val)
            p = p.next
        result.reverse() # result[::-1]
        return result
        # 如果需要逆读取链表
        # 方法2:增加额外空间:栈,来存储节点
        # 方法3:递归
        def visit(p):
            if not p:
                return []
            return visit(p.next)+[p.val]
        return visit(head)
Offer 08.双栈实现队列

栈:先进后出 ⟶ \longrightarrow 队列:先进先出。
负责进:栈1,负责出:栈2。
直接进栈1,直接出栈2,栈2若为空则将栈1 pop压入栈2。

class CQueue:

    def __init__(self):
        self.stack_in = []
        self.stack_out = []

    def appendTail(self, value: int) -> None:
        # 队列尾部插入整数
        self.stack_in.append(value)

    def deleteHead(self) -> int:
        # 队列头部删除整数,没有元素则返回 -1
        if not self.stack_in and not self.stack_out:
            return -1
        if not self.stack_out:
            while self.stack_in:
                self.stack_out.append(self.stack_in.pop())
        return self.stack_out.pop()

Offer 10-1斐波那契数列

动态规划DP:F[n]=F[n-1]+F[n-2]
节约空间只使用a、b来存储数据:b = b+a; a = b-a

class Solution:
    def fib(self, n: int) -> int:
        # DP
        if n==0:
            return 0

        MOD = 10**9+7
        a = 0
        b = 1
        for _ in range(1,n):
            a,b = b,(a+b) % MOD
        return b

Offer10-2.青蛙跳台阶问题
  • 一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶。求该青蛙跳上一个 n 级的台阶总共有多少种跳法
  • 动态规划DP: 10-1斐波那契数列
class Solution:
    def numWays(self, n: int) -> int:
        MOD = 10**9 + 7
        a = 0
        b = 1
        for _ in range(n):
            a,b = b,(a+b) % MOD
        return b

Offer 11.旋转数组的最小数字
  • 旋转有重复递增数组
  • numbers[mid] > numbers[right] → \rightarrow left = mid+1
  • numbers[mid] < numbers[right] → \rightarrow right = mid
  • right -= 1
class Solution:
    def minArray(self, numbers: List[int]) -> int:
        left = 0
        right = len(numbers)-1
        i = 1
        # Ns+1 < Nright < Nleft < Ns
        while left<right:
            mid = (left+right)//2
            if numbers[mid] > numbers[right]:
                left = mid+1
            elif numbers[mid] < numbers[right]:
                right = mid
            else:
                right -= 1
        return numbers[left]
Offer 15.二进制中1的个数
  1. 内置函数,count计算1个数
bin(n).count('1')
  1. 按位遍历
while n:
	count += n & 1
	n = n>>1
  1. n = n&(n-1), 迭代的次数为1的个数
while n:
	count += 1
	n &= n-1
Offer 18.删除链表节点
# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution:
    def deleteNode(self, head: ListNode, val: int) -> ListNode:
        # 单向链表
        p = head
        if head.val == val: return head.next
        while p and p.val != val: 
            bef,p = p,p.next # 双指针
        if p:
            bef.next = p.next
        return head
Offer 21. 调整数组顺序使奇数位于偶数前面

首尾双指针

class Solution:
    def exchange(self, nums: List[int]) -> List[int]:
        # 快速排序,前奇后偶
        i, j = 0, len(nums)-1
        while i < j:
            while i < j and nums[i]%2 != 0:
                i += 1
            while i < j and nums[j]%2 == 0:
                j -= 1
            if i < j:
                nums[i],nums[j] = nums[j],nums[i]
        return nums
Offer 22.链表中倒数第k个节点
# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def getKthFromEnd(self, head: ListNode, k: int) -> ListNode:
        # 输出该链表中倒数第k个节点
        # 解法1:list 存储空间增加
        # 解法2:先求链表长度n,再走n-k步
        save = []
        p = head
        while p:
            save.append(p)
            p = p.next
        return save[-k]
Offer 24.反转链表

三指针

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

class Solution:
    def reverseList(self, head: ListNode) -> ListNode:
        p2 = head
        if head:
            p3 = head.next
            head.next = None
            while p3:
                p1,p2,p3 = p2,p3,p3.next
                p2.next = p1
        return p2
Offer 29. 顺时针打印矩阵
class Solution:
    def spiralOrder(self, matrix: List[List[int]]) -> List[int]:
        # 从外向里以顺时针的顺序依次打印出矩阵每一个数字
        m = len(matrix)
        if m:
            n = len(matrix[0])
        else:
            return matrix

        result = []
        for i in range(min(m//2, n//2)):  
            result += matrix[i][i:n-i] # →

            for j in range(i+1,m-i): # ↓
                result.append(matrix[j][n-i-1])

            result += matrix[m-i-1][n-i-2:i:-1] # ←

            for j in range(m-i-1,i,-1): # ↑
                result.append(matrix[j][i])
		
		# 剩余情况
        i = min(m//2, n//2)
        if m - 2*i != 0:
            result += matrix[i][i:n-i]
            if n - 2*i != 0:
                for j in range(i+1,m-i):
                    result.append(matrix[j][n-i-1])
        return result
Offer30.包含min函数的栈
  • 题目:实现栈,并且要在O(1)时间取栈最小值

添加辅助栈(非严格单调递减):

  • 入栈:当入栈元素比辅助栈顶元素小或者辅助栈为空,入辅助栈。
  • 出栈:当出栈元素等于辅助栈顶元素,辅助栈顶出栈。
  • 最小值:辅助站顶元素
class MinStack:

    def __init__(self):
        """
        initialize your data structure here.
        """
        self.data = []
        self.assist = [] # 非严格递减

    def push(self, x: int) -> None:
        self.data.append(x)
        if not self.assist or self.assist[-1]>=x:
            self.assist.append(x)

    def pop(self) -> None:
        if self.data:
            if self.assist[-1]==self.data[-1]:
                self.assist.pop()
            self.data.pop()

    def top(self) -> int:
        if self.data:
            return self.data[-1]

    def min(self) -> int: # O(1)时间
        # return min(self.data)
        return self.assist[-1]


# Your MinStack object will be instantiated and called as such:
# obj = MinStack()
# obj.push(x)
# obj.pop()
# param_3 = obj.top()
# param_4 = obj.min()
Offer32-II.从上到下打印二叉树II

BFS

Offer39.数组中出现次数超过一半的数字

哈希字典

class Solution:
    def majorityElement(self, nums: List[int]) -> int:
        # 找出数组中出现的次数超过数组长度的一半的这个数字
        n = len(nums)
        count = {}
        for item in nums:
            count[item] = count.get(item,0)+1
            if count[item] > n//2:
                return item
Offer42.连续子数组的最大和

暴力:两层for循环

class Solution:
    def maxSubArray(self, nums: List[int]) -> int:
        # 方法1:暴力(超时)
        n = len(nums)
        F = [0]*(n+1)
        F[0] = nums[0]

        for i in range(1, n):
            F[i] = F[i-1] + nums[i]
        result = -101
        for i in range(0,n):
            for j in range(-1,i):
                result = max(result, F[i]-F[j])
        return result

DP: (位置i)

  • 如果dp[i-1]<=0,则dp[i]=nums[i]
  • dp[i-1]>0,则dp[i] = dp[i-1]+nums[i]
  • 返回dp最大值。
class Solution:
    def maxSubArray(self, nums: List[int]) -> int:
        # 时间复杂度为O(n)
        # 方法2:DP
        n = len(nums)
        dp = [0]*n
        dp[0] = nums[0]
        for i in range(1,n):
            dp[i] = max(dp[i-1]+nums[i], nums[i])
            # 若当前数加上当前累积子数组和 < 当前数,则从当前数为子数组开端
        return max(dp) # 返回所有子数组和最大值
Offer50.第一个只出现一次的字符
class Solution:
    def firstUniqChar(self, s: str) -> str:
        # 第一个只出现一次的字符
        save = {}
        for item in s:
            save[item] = save.get(item, 0) + 1
        for key, val in save.items():
            if val == 1:
                return key
        return ' '
Offer52.两个链表的第一个公共节点

俩列表存储俩链表,从尾到头判断相等。

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

class Solution:
    def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
        if not headA or not headB:
            return None
            
        list1 = [headA]
        p = headA
        while p.next:
            p = p.next
            list1.append(p)

        list2 = [headB]
        p = headB
        while p.next:
            p = p.next
            list2.append(p)
        
        i = -1
        l1,l2 = len(list1),len(list2)
        while i>=-min(l1,l2) and list1[i] == list2[i]:
            i -= 1

        if i == -1:
            return None
        return list1[i+1]
Offer53-Ⅰ
class Solution:
    def search(self, nums: List[int], target: int) -> int:
        if not nums:
            return 0
        # 方法一:二分查找
        n = len(nums)
        left, right = 0, n
        while left < right:
            mid = (left + right) // 2
            if nums[mid] < target:
                left = mid + 1
            elif nums[mid] > target:
                right = mid - 1
            else:
                break
        count = 0
        mid = (left + right) // 2
        i = mid
        while i<n and nums[i] == target:
            count += 1
            i += 1
        i = mid - 1
        while i>=0 and nums[i] == target:
            count += 1
            i -= 1
        return count

        # 2:顺序查找
        i = 0
        count = 0
        while i<len(nums) and nums[i] <= target:
            if nums[i] == target:
                count += 1
            i += 1
        return count
Offer54.二叉搜索树的第k大节点
class Solution:
    def kthLargest(self, root: TreeNode, k: int) -> int:
        # 右根左, count累加计数
        stack = []

        p = root
        while p:
            stack.append(p)
            p = p.right
        
        count = 0
        while stack:
            p = stack.pop()
            count += 1
            if count == k:
                return p.val
            if p.left:
                p = p.left
                while p:
                    stack.append(p)
                    p = p.right
Offer55-I.二叉树的深度

BFS

class Solution:
    def maxDepth(self, root: TreeNode) -> int:
        # BFS
        if not root:
            return 0
        stack = [root]
        count = 0
        while stack:
            for i in range(len(stack)):
                p = stack.pop(0)
                if p.left:
                    stack.append(p.left)
                if p.right:
                    stack.append(p.right)
            count += 1
        return count
Offer55-Ⅱ.平衡二叉树

递归

class Solution:
    def isBalanced(self, root: TreeNode) -> bool:
        # 某二叉树中任意节点的左右子树的深度相差不超过1,那么它就是一棵平衡二叉树
        def DFS(root):
            if not root:
                return 0, True
            l, l1 = DFS(root.left)
            r, l2 = DFS(root.right)
            label = l1 & l2
            if not -1<=l-r<=1:
                label = False
            return max(l,r)+1, label

        _, label = DFS(root)
        return label
Offer57.和为s的两个数字
class Solution:
    def twoSum(self, nums: List[int], target: int) -> List[int]:
        # 递增排序的数组
        save = dict(zip(nums, [0]*len(nums))) # list转字典,实现O(1)的查找
        for i,_ in save.items():
            if target-i in save:
                return [i,target-i]
Offer58-I.翻转单词顺序
class Solution:
    def reverseWords(self, s: str) -> str:
        i = 0
        result = ''
        while i < len(s):
            temp = ''
            while i < len(s) and s[i] != ' ':
                temp += s[i]
                i += 1
            if temp:
                result = temp + ' ' + result
            i += 1
        return result[:-1]
Offer58-Ⅱ.左旋转字符串
class Solution:
    def reverseLeftWords(self, s: str, n: int) -> str:
        # return s[n:]+s[:n]
        new = list(s)
        l = len(s)
        for i in range(l-n):
            new[i] = s[i+n]
        for i in range(n):
            new[l-n+i] = s[i]
        return ''.join(new)
Offer61.扑克牌中的顺子
class Solution:
    def isStraight(self, nums: List[int]) -> bool:
        # 判断是不是一个顺子, 0 可以看成任意数字
        nums.sort()
        n = len(nums)
        i = 0
        count = 0
        while i < n and nums[i] == 0:
            count += 1
            i += 1

        while i < n-1:
            temp = nums[i+1]-nums[i]-1
            if temp == -1:
                return False
            elif temp != 0:
                if count < temp:
                    return False
                count -= temp
            i += 1
        return True
Offer62.圆圈中最后剩下的数字
class Solution:
    def lastRemaining(self, n: int, m: int) -> int:
        # 逆推,数字个数从2~n
        count = 0
        for i in range(2, n+1):
            count = (count + m) % i
        return count

        # 直接列表,超时
        data = list(range(n))
        i = 0
        while n > 1:
            i = (i + m - 1) % n
            n -= 1
            del(data[i])
        return data[0]
Offer65.不用加减乘除做加法

二进制加法(补码)

class Solution:
    def add(self, a: int, b: int) -> int:
        # 在函数体内不得使用 “+”、“-”、“*”、“/” 四则运算符号
        # 位运算:^当前位, &进位

        x = 0xffffffff # 32位1
        print(a, b)
        a, b = a & x, b & x # 补码,正数补码不变,负数补码取反+1
        print(bin(a), b)
        while b:
            a, b = a ^ b, (a & b) << 1 & x
        print(bin(0x7fffffff))
        return a if a <= 0x7fffffff else ~(a ^ x) # 31位1,若>31位1 ~(a ^ x)


14. 最长公共前缀

暴力解法:横向扫描

class Solution:
    def longestCommonPrefix(self, strs: List[str]) -> str:
        if not strs: # strs空的情况
            return ""

        temp = strs[0]
        # 双重循环
        for i in range(1, len(strs)):
            temp = temp[:min(len(temp), len(strs[i]))]
            for j in range(len(temp)):
                if temp[j] != strs[i][j]:
                    temp = temp[:j]
                    break
        return temp

220.存在重复元素III❓

  • 题目描述]:整数数组 nums 和两个整数 k 和 t 。判断是否存在两个不同下标 i 和 j,使得 abs(nums[i] - nums[j]) <= t ,同时又满足 abs(i - j) <= k 。存在返回 true,不存在返回 false。

滑动窗+有序数组(O(1)的查、增、删)
C++中 set/multiset/map,Java中TreeSet、TreeMap,Python中sortedcontainers(转自☞这里 )。


1143.最长公共子序列

  • 题目描述:俩字符串text1和text2,返回最长公共子序列的长度。
  • 子序列:由原字符串在不改变字符的相对顺序的情况下删除某些字符(也可以不删除任何字符)后组成的新字符串。

动态规划
t e x t 1 [ : i + 1 ] text1[:i+1] text1[:i+1] t e x t 2 [ : j + 1 ] text2[:j+1] text2[:j+1]的最长公共子序列长度为 d p [ i + 1 ] [ j + 1 ] dp[i+1][j+1] dp[i+1][j+1],状态转移方程:

if text1[:i+1]==text2[:j+1]:
	dp[i+1][j+1] = dp[i][j]+1
else:
	dp[i+1][j+1] = max(dp[i][j+1], dp[i+1][j])

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

注:面试笔试出现概率高
同:剑指 Offer 48. 最长不含重复字符的子字符串

  • 题目描述:找出字符串中不含有重复字符的最长子串的长度。

暴力搜索:

滑动窗口:❓


28.实现strStr()

  • 题目描述:

字符串匹配KMP
前缀表(用来记录匹配失败后该跳回的位置)
子串中当前位置前缀表值=之前(包括当前位置)的字符串,前缀后缀最大重合数。eg. “ababa”->“aba” 3
匹配失败后,子串指向前一位的前缀值的位置。
推荐视频


面试题56-I.数组中数字出现的次数

  • 题目描述:一个整型数组 nums 里除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。

思路:每次对当前列表中未查找的第一个元素遍历列表,若有与该元素相同的元素存在则删除这俩元素,若无相同则保留元素。

python

class Solution(object):
    def singleNumbers(self, nums):
        """
        :type nums: List[int]
        :rtype: List[int]
        """
        i = 0
        while len(nums) > i:
            flag = 0
            for j in range(i+1, len(nums)):
                if nums[i] == nums[j]:
                    del nums[j]
                    del nums[i]
                    flag = 1
                    break
            if flag == 0:
                i += 1
        print(i)
        return nums
Code算法_第1张图片

存在的问题:执行用时过长,时间复杂度没有达到O(n)

官方使用的是分组异或
异或 ^ 操作:

  • 任何数和0异或后不变
  • 相同为0,不同为1

e.g. 若找出数组中唯一一个只出现一次的数,则只需对所有元素进行一次异或操作:
a1 ^ a2 ^ a3 ^ a4 ^ a5… ^ an
两两相同的元素异或之后得0,只剩下出现一次那个数

现在题目是找出两个只出现一次的数,分组异或方法❓
如何分组?先到这里。


137.只出现一次的数字Ⅱ

  • 题目描述:只有一个数只出现一次其余都出现三次
  • 相似题目:面试题56-l

位运算

思路转载自这里
将十进制数转换成32位二进制数,各个位数十进制相加,结果不能被3整除的位置为1,能整除为0,得到只出现一次的元素的二进制数。
x二进制数的第i位:(x >> i) & 1>>右移运算符,&按位与运算符。
相加后若当前位不为3的倍数,则1<左移i位做|或运算。python没有符号位,i==31最高位时,为-2^31。

状态机❓

二进制表示出现三次(00,01,10)。

拓展

  1. 只有一个数只出现一次其余都出现两次:异或(a^ b^ a=b)。
  2. 只有一个数只出现一次其余都出现奇数次

554.砖墙

  • 题目描述:由 n 行砖块组成的砖墙。这些砖块高度相同(也就是一个单位高)但是宽度不同。每一行砖块的宽度之和应该相等。二维数组 wall,wall[i] 是一个代表从左至右每块砖的宽度的数组。画一条 自顶向下 的、穿过 最少 砖块的垂线,返回穿过砖块的数量。

思路:

  1. i 每次跳跃最小一块砖长度(i = 当前0列最小的数)
  2. 计算第 i 列需要穿过的砖块数量:若某行第一块砖长度==i,则不需要穿过。若某行第一块砖长度>=i,则合并第一第二块砖长。
  3. 重复1.2步骤,直到 i 到达砖墙尾部。
  4. 所有列中最小的穿过砖块的数量即为所得。
class Solution:
    def leastBricks(self, wall: List[List[int]]) -> int:
        slice_0 = [i[0] for i in wall] # 0列切片
        i = min(slice_0)
        min_cross = len(wall)

        while i !=wall[0][0] or len(wall[0])!=1: # i==wall[0][0] and len(wall)==1结束
            count = 0 # 第i列需要穿过的砖块数量
            for j in range(len(wall)): # 计算j行
                if wall[j][0]>i:
                    count+=1
                elif wall[j][0]==i:
                    # count 不变
                    # 合并 位置0和1
                    wall[j][0] += wall[j][1] 
                    wall[j].pop(1)
                    # 更新切片
                    slice_0[j] = wall[j][0]
                elif wall[j][0]<i:
                    count+=1
                     # 合并
                    wall[j][0] += wall[j][1] 
                    wall[j].pop(1)
                    # 更新切片
                    slice_0[j] = wall[j][0]

            i = min(slice_0)
            min_cross = min(min_cross, count)
        return min_cross

题解提供思路:哈希❓


7.整数反转

  • 题目描述:返回将32位有符号整数 x 数字部分反转后的结果。 − 2 31 ≤ x ≤ 2 31 − 1 -2^{31} \le x \le 2^{31} - 1 231x2311
class Solution:
    def reverse(self, x: int) -> int:
        # 数字反转
        # 32位有符号整数: -2^31 <= x <= 2^31 - 1
        border = 2**(31)
        if x<0:
            multi_base = -1
            x = -x
        else:
            multi_base = 1
        count = 0
        for i in str(x):
            count += multi_base*int(i)
            multi_base *= 10
        if count > border-1 or count< -border: # 溢出判断
            count = 0
        return count

若不使用str(x)int(i)强制转换,数学方式:
c o u n t = c o u n t ∗ 10 + x % 10 x = x / / 10 count = count*10 + x\%10\\ x = x//10 count=count10+x%10x=x//10
由于题目里面说明:假设环境不允许存储 64 位整数(有符号或无符号)
所以将溢出判断加入到while循环里:

	while x!=0:
		if count > border-1 or count< -border: # 溢出判断
			return 0  # return count = 0
	    count = count*10 + x%10
	    x = x//10
	count *= multi_base

1473.粉刷房子Ⅲ

  • 题目描述:m 个房子 n 种颜色(1~n,0为未涂色),houses[i]: 第i个房子的颜色;cost[i][j]: 第 i 个房子涂成 j+1 花费。连续相同颜色尽可能多的房子称为一个街区。找最小花费的涂色方案,使得所有房子都被涂色后组成target个街区。
  • houses[i], cost[i][j], m, n, target

动态规划,参考☞这里

class Solution:
    def minCost(self, houses: List[int], cost: List[List[int]], m: int, n: int, target: int) -> int:
        # f[i][j][k] 第i间房子,颜色j,分区数k
        INF = float("inf")
        # 初始化
        f = [[[0]*(target+1) for j in range(n)] for i in range(m+1)]

        # i =0 k!=0时INF
        for j in range(n):
            for k in range(target+1):
                if k != 0:
                    f[0][j][k] = INF

        for i in range(1,m+1):
            if houses[i-1]==0: # 未上色
                # f[i][j][k] = min(f[i−1][j][k],f[i−1][p][k−1])+cost[i][j]
                for j in range(n):
                    f[i][j][0] = INF ##
                    for k in range(1,target+1):
                        f[i][j][k] = f[i-1][j][k]
                        for p in range(n):
                            if p != j:
                                f[i][j][k] = min(f[i][j][k], f[i-1][p][k-1])
                        f[i][j][k] += cost[i-1][j]
            else: # 已上色
                # f[i][houses[i]][k] = min(f[i-1][j][k], f[i-1][p][k-1])
                for j in range(n):
                    f[i][j][0] = INF
                    for k in range(1,target+1):
                        if j+1==houses[i-1]:
                            f[i][j][k] = f[i-1][j][k]
                            for p in range(n):
                                if p!=j:
                                    f[i][j][k] = min(f[i][j][k], f[i-1][p][k-1])
                        else:
                            f[i][j][k] = INF
        # m屋子都涂了且有target个街区的数据里面找最小值
        min_data = f[m][0][target]
        for p in range(1,n):
            min_data = min(min_data, f[m][p][target])
        if min_data==INF:
            return -1
        else:
            return min_data

i,j,k之间从0开始还是从1开始debug好久。叹气~
最初 i = 0 → f [ 0 ] [ ] [ k ! = 0 ] = I N F , f [ 0 ] [ ] [ 0 ] = 0 i=0\rightarrow f[0][ ][k!=0] = INF, f[0][ ][0] = 0 i=0f[0][][k!=0]=INF,f[0][][0]=0
后面 i ! = 0 → f [ i ] [ ] [ 0 ] = I N F i!=0\rightarrow f[i][ ][0]=INF i!=0f[i][][0]=INF


198.打家劫舍

  • 题目描述:在同一晚上不进入两间相邻的房屋,求一夜之内能够偷窃到的最高金额。

动态规划
d p [ i ] = m a x ( d p [ i − 2 ] + n u m s [ i ] , d p [ i − 1 ] ) dp[i] = max(dp[i-2]+nums[i], dp[i-1]) dp[i]=max(dp[i2]+nums[i],dp[i1])

class Solution:
    def rob(self, nums: List[int]) -> int:
        """
        dp[0] = nums[0]
        dp[1] = max(nums[0], nums[1])
        dp[i] = max(dp[i-2]+nums[i],dp[i-1])
        """
        dp = [0]*len(nums)
        dp[0] = nums[0]
        if len(nums)>1:
            dp[1] = max(nums[:2])
        for i in range(2,len(nums)):
            dp[i] = max(dp[i-2]+nums[i], dp[i-1])
        return dp[len(nums)-1]

740.删除并获得点数

  • 题目描述:每次选择任意一个nums[i],删除它并获得它的点数。并删除每个等于nums[i]- 1或nums[i] + 1的元素。求能获得的最大点数。

动态规划,相似题198.打家劫舍
d p [ i ] = m a x ( d p [ i − 2 ] + i ∗ b u c k e t [ i ] , d p [ i − 1 ] ) dp[i] = max(dp[i-2]+i*bucket[i], dp[i-1]) dp[i]=max(dp[i2]+ibucket[i],dp[i1]),bucket[i]为 i i i出现的次数。

class Solution:
    def deleteAndEarn(self, nums: List[int]) -> int:
        MAX = max(nums)
        bucket = [0]*(MAX+1) # 存储每个数字出现的次数
        dp = []
        for i in nums:
            bucket[i]+=1

        i = 1
        while i<=MAX and bucket[i]==0:
            i += 1
        dp.append(i*bucket[i])  # dp[0]
        if i == MAX:
            return dp[0]
        i += 1
        
        # dp[1]
        if bucket[i]!=0:
            dp.append(max(dp[0],i*bucket[i]))  
        else:
            while i<=MAX and bucket[i]==0:
                i += 1
            dp.append(max(dp[0],dp[0]+i*bucket[i]))

        i += 1
        while i<=MAX:
            dp.append(max(dp.pop(0)+i*bucket[i], dp[0]))
            i += 1
        return dp[1]      

1720.解码异或后的数组

  • 题目描述:非负整数数组arr[ : n]通过编码变成encoded[ : n-1]整数数组,encoded[ i ] = arr[ i ] XOR arr[ i+1 ]。已知encoded和arr[0]求arr?

a ⊕ b = c → a ⊕ c = b → b ⊕ c = a a \oplus b=c \rightarrow a\oplus c=b \rightarrow b\oplus c=a ab=cac=bbc=a
所以: a r r [ i + 1 ] = e n c o d e d [ i ] ⊕ a r r [ i ] arr[ i+1 ] = encoded[ i ] \oplus arr[ i ] arr[i+1]=encoded[i]arr[i]

class Solution:
    def decode(self, encoded: List[int], first: int) -> List[int]:
        a = [first]
        for i in range(len(encoded)):
            a.append(encoded[i]^a[i])
        return a

1486.数组异或操作

  • 题目描述:nums[i] = start + 2i,nums长度0~n,返回nums所有元素按位异或后结果。

计算结果的第i位:

  1. 将nums数组中第i位提取出来nums[j] >> i & 1做异或^运算。
  2. 将异或结果加入最后的结果中temp<
for j in range(n):
	temp ^= nums[j] >> i & 1
result += temp<
class Solution:
    def xorOperation(self, n: int, start: int) -> int:
        nums = [0]*n
        for i in range(n):
            nums[i] = start+2*i
        i = 0
        result = 0
        while nums[n-1]>>i!=0:
            temp = 0
            for j in range(n):
                temp ^= nums[j] >> i & 1
            result += temp<<i
            i+=1
        return result		

看了题解,想复杂了,直接异或即可:

class Solution:
    def xorOperation(self, n: int, start: int) -> int:
		# 直接异或
	     result = 0
	     for i in range(n):
	         result ^= start+2*i
	     return result

方法二:
数学思维,☞这里。(start)^(start+2)^(start+4)^(start+6)^...^(start+2(n-1))
变为:(s ^ (s+1) ^ (s+2) ^ … ^ (s+n-1)) * 2 + e
其中 s = ⌊ start 2 ⌋ s=\lfloor \frac{\textit{start}}{2} \rfloor s=2start ∗ 2 *2 2表示左移一位,所以 e e e 表示运算结果的最低位。


1723.完成所有工作的最短时间❓

  • 题目描述:jobs[i]完成第i项工作花费的时间。分给k位工人,每项工作一位工人。求工人最大工作时间(总和)的最小值。

背包问题?图论? ⟹ \Longrightarrow 工作量要分的平均

1. 动态规划+状态压缩

来自☞这里。
状态压缩:用n位二进制整数表示n个工作的分配情况(实际只需要一个变量)。
状态转移方程: f [ i ] [ j ] = m i n j ′ ∈ j { m a x ( f [ i − 1 ] [ C j j ′ ] , s u m [ j ′ ] ) } f[i][j] = min_{j' \in j}\{max(f[i-1][Cjj'], sum[j'])\} f[i][j]=minjj{max(f[i1][Cjj],sum[j])} f [ i ] [ j ] f[i][j] f[i][j]:给前 i i i个人分配工作,分配情况为 j j j时完成所有工作的最短时间。
题解python直译竟然还超时了,桑心

import math
class Solution:
    def minimumTimeRequired(self, jobs: List[int], k: int) -> int:
        # 题解思路:动态规划+状态压缩
        MAX = float('inf')
        n = len(jobs)
        sums = [0]*(1 << n)
        dp = [[0]*(1 << n) for i in range(k)]
        for i in range(1,1<<n):
            x = int(math.log(i&(-i),2)) # 2^x = i&(-i) 二进制尾0个数
            y = i-(1<<x)
            sums[i] = sums[y] + jobs[x]
        dp[0] = sums

        for i in range(1,k):
            for j in range(1<<n):
                minn = MAX
                x = j
                while x!=0:
                    minn = min(minn, max(dp[i-1][j-x],sums[x]))
                    x = (x-1)&j
                dp[i][j] = minn
        return dp[k-1][(1<<n)-1]

1482.制作m束花所需的最少天数

  • 题目描述:数组 bloomDay存储第 i朵花会在 bloomDay[i]盛开。需要 m束花,每束花需要相邻的 k朵花。问需要等的最少天数。

二分法:需要等待的最少天数 m i n ( b l o o m D a y ) < d a y < m a x ( b l o o m D a y ) min(bloomDay)min(bloomDay)<day<max(bloomDay)
思路来自(☞゚ヮ゚)☞这里,讲解清晰易懂。

class Solution:
    def minDays(self, bloomDay: List[int], m: int, k: int) -> int:
        # m束花,每束使用相邻k朵花,day>bloomDay[i]才可以摘取
        if m*k>len(bloomDay):
            return -1
        left = min(bloomDay)
        right = max(bloomDay) # [left~mid~right)
        while left<right:
            mid = (left+right)//2
            if is_satisfy(bloomDay,m,k,mid):
                right = mid # [left,mid)
            else:
                left = mid+1 # [mid+1,right)
        return left

def is_satisfy(bloomDay,m,k,mid):
    count_m = 0
    i = 0
    while i < len(bloomDay):
        while i < len(bloomDay) and bloomDay[i] > mid:
            i+=1
        count_k = 0
        while i < len(bloomDay) and bloomDay[i] <= mid: # 连续花
            count_k+=1
            i+=1
            if count_k==k: # 取了k朵重新开始计数
                count_m+=1
                if count_m == m:
                    return True
                break       
    return False

二分法区间边界如何界定??


872.叶子相似的树

DFS

# 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 leafSimilar(self, root1: TreeNode, root2: TreeNode) -> bool:
		# DFS
        if DFS(root1)==DFS(root2):
            return True
        else:
            return False
        
        
def DFS(root):
    leaf = [] # 叶值序列
    p = root
    stack = [p]
    while p.left:
        p = p.left
        stack.append(p) # 左子树入栈

    while stack:
        p = stack.pop()
        if p.right:
            p = p.right
            stack.append(p) # 栈顶元素右节点入栈
            while p.left: # 并将该节点所有左子树节点入栈
                p = p.left
                stack.append(p)
        elif not p.left:
            leaf.append(p.val) # 叶节点
    return leaf

1734.解码异或后的排列

  • 题目描述:与1720.解码异或后的数组相似: e n c o d e d [ i ] = p e r m [ i ] ⊕ p e r m [ i + 1 ] encoded[i] = perm[i] \oplus perm[i + 1] encoded[i]=perm[i]perm[i+1]。但不给perm[0],已知encoded为1~n(n=len(perm))整数排列,n为奇数,求perm.

e n c o d e d [ 0 ] = p e r m [ 0 ] ⊕ p e r m [ 1 ] encoded[0] = perm[0] \oplus perm[1] encoded[0]=perm[0]perm[1]
e n c o d e d [ 1 ] = p e r m [ 1 ] ⊕ p e r m [ 2 ] encoded[1] = perm[1] \oplus perm[2] encoded[1]=perm[1]perm[2]
e n c o d e d [ 2 ] = p e r m [ 2 ] ⊕ p e r m [ 3 ] encoded[2] = perm[2] \oplus perm[3] encoded[2]=perm[2]perm[3]
e n c o d e d [ 3 ] = p e r m [ 3 ] ⊕ p e r m [ 4 ] encoded[3] = perm[3] \oplus perm[4] encoded[3]=perm[3]perm[4]
… \ldots
e n c o d e d [ 1 ] ⊕ e n c o d e d [ 3 ] ⊕ e n c o d e d [ 5 ] . . . ⊕ e n c o d e d [ n − 2 ] = p e r m [ 1 ] ⊕ p e r m [ 2 ] … p e r m [ n − 1 ] encoded[1]\oplus encoded[3]\oplus encoded[5]...\oplus encoded[n-2] = perm[1]\oplus perm[2]\ldots perm[n-1] encoded[1]encoded[3]encoded[5]...encoded[n2]=perm[1]perm[2]perm[n1],由此可得 p e r m [ 0 ] perm[0] perm[0].

class Solution:
    def decode(self, encoded: List[int]) -> List[int]:
        # n 是奇数
        n = len(encoded)+1
        perm = [0]
        
        for i in range(n//4*4,n+1):
            perm[0] ^= i # 1^2^3...^n
        for i in range(0,n//2):
            perm[0] ^= encoded[2*i+1]
        
        for j in range(n-1):
            perm.append(perm[j]^encoded[j])
        return perm

1310.子数组异或查询

F [ i ] = a r r [ 0 ] ⊕ a r r [ 1 ] ⊕ a r r [ 2 ] . . . ⊕ a r r [ i ] F[i]=arr[0]\oplus arr[1]\oplus arr[2] ... \oplus arr[i] F[i]=arr[0]arr[1]arr[2]...arr[i]
X O R [ L , R ] = a r r [ L ] ⊕ a r r [ L + 1 ] . . . ⊕ a r r [ R ] = F [ L − 1 ] ⊕ F [ R ] XOR[L,R] = arr[L]\oplus arr[L+1] ... \oplus arr[R]=F[L-1]\oplus F[R] XOR[L,R]=arr[L]arr[L+1]...arr[R]=F[L1]F[R]

import numpy as np
class Solution:
    def xorQueries(self, arr: List[int], queries: List[List[int]]) -> List[int]:
        # 查询数组queries[i] = [Li, Ri]
        result = []
        n = len(arr)
        F = [0]*(n+1) # 只需要一维
        F[0] = arr[0]
        for j in range(1,n):
            F[j] = F[j-1]^arr[j]

        for L,R in queries:
            result.append(F[L-1]^F[R])
        return result

1269.停在原地的方案数

动态规划
d p [ i ] [ j ] = d p [ i − 1 ] [ j − 1 ] + d p [ i − 1 ] [ j ] + d p [ i − 1 ] [ j + 1 ] dp[i][j]=dp[i−1][j−1]+dp[i−1][j]+dp[i−1][j+1] dp[i][j]=dp[i1][j1]+dp[i1][j]+dp[i1][j+1]
s t e p s = i , p r e s e n t = j steps = i, present = j steps=i,present=j
i > j i>j i>j不考虑为0, i = j i=j i=j为1。

import numpy as np
class Solution:
    def numWays(self, steps: int, arrLen: int) -> int:
        # 恰好执行 steps 次操作以后,指针仍然指向索引 0 处的方案数
        MODULO = 10**9 + 7
        MIN = min(arrLen,steps) # 不加这句空间会爆
        dp = [[0]*MIN for _ in range(steps)]

        dp[0][0] = 1
        for i in range(1,steps):
            for j in range(0,MIN):
                dp[i][j]=dp[i-1][j] % MODULO # 取模,不然位数会超(溢出)
                if j>=1:
                    dp[i][j]+=dp[i-1][j-1] % MODULO
                if j<MIN-1:
                    dp[i][j]+=dp[i-1][j+1] % MODULO
        return (dp[steps-1][0]+dp[steps-1][1]) % MODULO

12.整数转罗马数字

  • 转换规则:1,5,10,50,100,500,1000:I,V,X,L,C,D,M

没啥技术含量的代码:

class Solution:
    def intToRoman(self, num: int) -> str:
        result = ""

        Roman_dict = {'M':1000,'CM':900,'D':500,'CD':400,'C':100,'XC':90,'L':50,'XL':40,'X':10,'IX':9,'V':5,'IV':4,'I':1}

        for ro,data in Roman_dict.items():
            result += ro * (num//data)
            num %= data
		return result

13.罗马数字转整数

逆:12.整数转罗马数字
没啥技术含量代码:(思路:该数比后一数小,-该数,否则 +该数得结果)

class Solution:
    def romanToInt(self, s: str) -> int:
        # 罗马数字,将其转换成整数
        roman_dict = {'I':1,'V':5,'X':10,'L':50,'C':100,'D':500,'M':1000}
        # IV,IX,XL,XC,CD,CM
        
        result = 0
        temp = int(roman_dict[s[0]])
        for i in range(1,len(s)):
            data = int(roman_dict[s[i]])
            if temp < data:
                result -= temp
            else:
                result += temp
            temp = data
        result += temp
        return result

208.实现Trie(前缀树)

  • 实现字典树,关键是数据结构children : list[26], isEnd : boolean.

注:ord(letter) - 97 ASCII转 int,或者 ord(ch) - ord("a").

class Trie:
    # 前缀树:用于高效地存储和检索字符串数据集中的键
    def __init__(self):
        """
        Initialize your data structure here.
        """
        self.children = [None]*26  # 26位小写字母
        self.isEnd = False  # 判断当前是否为字符串结尾
        
    def insert(self, word: str) -> None:
        """
        Inserts a word into the trie.
        """
        children = self.children
        for letter in word:
            p = children[ord(letter)-97]
            if p:
                children = p.children
            else:
                p = Trie()
                children[ord(letter)-97] = p
                children = p.children
        p.isEnd = True
        
    def search(self, word: str) -> bool:
        """
        Returns if the word is in the trie.
        """
        children = self.children
        for letter in word:
            p = children[ord(letter)-97]
            if p:
                children = p.children
            else:
                return False
        if p.isEnd:
            return True
        else:
            return False
            
    def startsWith(self, prefix: str) -> bool:
        """
        Returns if there is any word in the trie that starts with the given prefix.
        """
        children = self.children
        for letter in prefix:
            p = children[ord(letter)-97]
            if p:
                children = p.children
            else:
                return False
        return True


# Your Trie object will be instantiated and called as such:
# obj = Trie()
# obj.insert(word)
# param_2 = obj.search(word)
# param_3 = obj.startsWith(prefix)

421.数组中两个数的最大异或值

  • 题目描述: n u m s [ i ] ⊕ n u m s [ j ] nums[i] \oplus nums[j] nums[i]nums[j] 的最大值
    二重循环枚举会时间超限。
    字典树
class Trie:
    # 前缀树:用于高效地存储和检索字符串数据集中的键
    def __init__(self):
        """
        Initialize your data structure here.
        """
        self.children = [None]*2

    def insert(self, word: str) -> None:
        """
        Inserts a word into the trie.
        """
        p = self
        i = 30
        while i>=0:
            num = (word >> i) & 1 # 取数
            if p.children[num]:
                p = p.children[num]
            else: 
                new = Trie()
                p.children[num] = new
                p = new
            i-=1

    def check(self, word: str): # 计算树中与word异或结果最大值
        p = self
        i = 30
        x = 0
        while i>=0:
            num = (word >> i) & 1 # 取数
            # num:0,尽量取1;num:1,尽量取0
            if num == 0:
                if p.children[1]:
                    p = p.children[1]
                    x = x*2+1 # 异或结果
                else:
                    p = p.children[0]
                    x = x*2
            else:
                if p.children[0]:
                    p = p.children[0]
                    x = x*2+1
                else:
                    p = p.children[1]
                    x = x*2
            i-=1
        return x

class Solution:
    def findMaximumXOR(self, nums: List[int]) -> int:
        # nums[i] XOR nums[j] 的最大运算结果
        # 最大:相异位数越多
        # O(n)时间
        # 创建树
        root = Trie()

        x = 0
        for i in range(len(nums)-1):
            root.insert(nums[i])
            x = max(x, root.check(nums[i+1]))
        return x

421.数组中两个数的最大异或值

字典树,参考题解v(☞゚ヮ゚)☞这里
a i a_i ai枚举nums,并通过字典树快速找到能使 a i ⊕ a j a_i\oplus a_j aiaj最大的 a j a_j aj

class Trie:
    # 前缀树:用于高效地存储和检索字符串数据集中的键
    def __init__(self):
        """
        Initialize your data structure here.
        """
        self.children = [None]*2

    def insert(self, word: str) -> None:
        """
        Inserts a word into the trie.
        """
        p = self
        i = 30
        while i>=0:
            num = (word >> i) & 1 # 取数
            if p.children[num]:
                p = p.children[num]
            else: 
                new = Trie()
                p.children[num] = new
                p = new
            i-=1

    def check(self, word: str): # 计算树中与word异或结果最大值
        p = self
        i = 30
        x = 0
        while i>=0:
            num = (word >> i) & 1 # 取数
            # num:0,尽量取1;num:1,尽量取0
            if num == 0:
                if p.children[1]:
                    p = p.children[1]
                    x = x*2+1 # 异或结果
                else:
                    p = p.children[0]
                    x = x*2
            else:
                if p.children[0]:
                    p = p.children[0]
                    x = x*2+1
                else:
                    p = p.children[1]
                    x = x*2
            i-=1
        return x

class Solution:
    def findMaximumXOR(self, nums: List[int]) -> int:
        # nums[i] XOR nums[j] 的最大运算结果
        # O(n)时间
        root = Trie()
        x = 0
        for i in range(len(nums)-1):
            root.insert(nums[i])
            x = max(x, root.check(nums[i+1]))
        return x

993.二叉树的堂兄弟节点

  • 判断是否为堂兄节点:两个节点深度相同,但父节点不同。二叉树具有唯一值。

广度优先变形:层次遍历(每次根据当前队列长度,将节点遍历一遍),好处:不需额外添加深度int.

# 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 isCousins(self, root: TreeNode, x: int, y: int) -> bool:
        # 层次遍历
        stack = [root] # 队列
        while stack:
            parent = []
            for _ in range(len(stack)): # 当前层节点个数
                p = stack.pop(0)
                if p.left:
                    if p.left.val != x and p.left.val != y:
                        stack.append(p.left)
                    else:
                        parent.append(p.val) 
                if p.right:
                    if p.right.val != x and p.right.val != y:
                        stack.append(p.right)
                    else:
                        parent.append(p.val) 
            if parent: # 有俩父且不相等则为True
                if len(parent) == 2 and parent[0]!=parent[1]:
                    return True
                else:
                    return False
        return False

1442.形成两个异或相等数组的三元组数目

  • 数组arr中取三个下标 i , j , k i,j,k i,j,k, 0 ≤ i < j ≤ k < a r r . l e n g t h 0 \leq i < j \leq k < arr.length 0i<jk<arr.length。求 a = b a=b a=b取法数量。
  • a = a r r [ i ] ⊕ a r r [ i + 1 ] ⊕ . . . ⊕ a r r [ j − 1 ] a = arr[i] \oplus arr[i + 1] \oplus ... \oplus arr[j - 1] a=arr[i]arr[i+1]...arr[j1]
  • b = a r r [ j ] ⊕ a r r [ j + 1 ] ⊕ . . . ⊕ a r r [ k ] b = arr[j] \oplus arr[j + 1] \oplus ... \oplus arr[k] b=arr[j]arr[j+1]...arr[k]

求a、b值见1310.子数组异或查询
a = F [ j − 1 ] ⊕ F [ i − 1 ] b = F [ k ] ⊕ F [ j − 1 ] a = b ⇒ F [ i − 1 ] = F [ k ] 只 需 确 定 i , k ; j ∈ ( i , k ] . a = F[j-1]\oplus F[i-1]\\ b = F[k]\oplus F[j-1]\\ a=b\Rightarrow F[i-1]=F[k] \\ 只需确定i,k; j \in (i,k]. a=F[j1]F[i1]b=F[k]F[j1]a=bF[i1]=F[k]i,k;j(i,k].

class Solution:
    def countTriplets(self, arr: List[int]) -> int:
        n = len(arr)
        F = [0]*(n+1) # F[n]是为了防止找F[0]时溢出F[-1]=0
        F[0] = arr[0]
        for i in range(1,n):
            F[i] = F[i-1]^arr[i]
        
        count = 0

        for i in range(n-1):
            for k in range(i+1,n):
               # a = F[j-1]^F[i-1]
               # b = F[k]^F[j-1]
               # F[i-1]?=F[k] 只需限定i,k; j \in (i,k].
                if F[i-1]==F[k]:
                    count += k-i
                
        return count

692.前k个高频单词

哈希字典+排序

class Solution:
    def topKFrequent(self, words: List[str], k: int) -> List[str]:
        # 返回前 k 个出现次数最多的单词
        # O(n log k) 时间复杂度和 O(n) 空间复杂度
        count = {}  # (哈希表)字典统计出现次数
        for i in words:
            count[i] = count.get(i,0) + 1

        # 排序
        result = []
        for key, val in count.items():
                result.append((key, val))

        for i in range(k):
            temp = []
            for j in range(i+1,len(result)):
                if result[i][1] < result[j][1] or (result[i][1] == result[j][1] and result[i][0]>result[j][0]):
                    temp = result[i]
                    result[i] = result[j]
                    result[j] = temp

        return [result[i][0] for i in range(k)]

1035.不相交的线

动态规划,类似:1143.最长公共子序列
F [ i ] [ j ] F[i][j] F[i][j] n u m s 1 [ : i ] nums1[:i] nums1[:i] n u m s 2 [ : j ] nums2[:j] nums2[:j] 的最大不相交线个数。

  • 这里 F F F数组我取的大小是 l 1 ∗ l 2 l1*l2 l1l2,并单独判断了边界值 F [ : ] [ 0 ] F[:][0] F[:][0] F [ 0 ] [ : ] F[0][:] F[0][:]
    待改进:大小取 ( l 1 + 1 ) ∗ ( l 2 + 1 ) (l1+1)*(l2+1) (l1+1)(l2+1),边界值均为0。 F [ i + 1 ] [ j + 1 ] F[i+1][j+1] F[i+1][j+1] n u m s 1 [ : i ] nums1[:i] nums1[:i] n u m s 2 [ : j ] nums2[:j] nums2[:j] 的最大不相交线个数。
  • 动态转移方程:
    F [ i ] [ j ] = F [ i − 1 ] [ j − 1 ] + 1 ,  if  n u m s 1 [ i ] = = n u m s 2 [ j ] = m a x ( F [ i − 1 ] [ j ] , F [ i ] [ j − 1 ] ) ,  else  . F[i][j] = F[i-1][j-1]+1, \text{ if } nums1[i]==nums2[j]\\ =max(F[i-1][j], F[i][j-1]), \text{ else }. F[i][j]=F[i1][j1]+1, if nums1[i]==nums2[j]=max(F[i1][j],F[i][j1]), else .
class Solution:
    def maxUncrossedLines(self, nums1: List[int], nums2: List[int]) -> int:
        # 求最大连线数
        l1 = len(nums1)
        l2 = len(nums2)
        F = [[0]*l2 for _ in range(l1)]
        # 边界值
        F[0][0] = 1 if nums1[0] == nums2[0] else 0
        for i in range(1,l1):
            if nums1[i] == nums2[0]:
                F[i][0] = 1
            else:
                F[i][0] = F[i-1][0]

        for j in range(1,l2):
            if nums1[0] == nums2[j]:
                F[0][j] = 1
            else:
                F[0][j] = F[0][j-1]
       
		# 动态转移
        for i in range(1,l1):
            for j in range(1,l2):
                # F[i][j] = max(F[i-1][j],F[i][j-1])
                # if nums1[i] == nums2[j]:
                #     F[i][j] = max(F[i-1][j-1]+1,F[i][j])
                # 上述改进:
                if nums1[i] == nums2[j]:
                    F[i][j] = F[i-1][j-1]+1
                else:
                	F[i][j] = max(F[i-1][j],F[i][j-1])
        return F[l1-1][l2-1]

1707.与数组中元素的最大异或值

  • n u m s nums nums数组和 q u e r i e s [ x , m ] queries[x,m] queries[x,m],求 m a x ( n u m s [ j ] ⊕ x ) , n u m s [ j ] < m max(nums[j] \oplus x), nums[j]max(nums[j]x),nums[j]<m.

字典树: 208.实现Trie(前缀树)
给nums和queries排序,将nums中小于m的数先插入字典树中,再计算字典树中最大异或值。

import numpy as np
import math
class Trie():
    def __init__(self):
        self.left = None # 0
        self.right = None # 1
   
class Solution:
    def maximizeXor(self, nums: List[int], queries: List[List[int]]) -> List[int]:
        n = len(nums)
        a = len(queries)
        # 排序
        nums.sort()
        index = (np.argsort([m for _,m in queries]))
        answer = [0]*a

        head = Trie()
        l = int(math.log(nums[n-1],2)) # 树高度

        def insert(num):
        	# 插入
            i = l
            p = head
            while i >= 0:
                t = num >> i & 1
                i -= 1
                if t == 0:
                    if not p.left:
                        new = Trie()
                        p.left = new
                    p = p.left
                if t == 1:
                    if not p.right:
                        new = Trie()
                        p.right = new
                    p = p.right
        def search(x):
        	# 计算最大异或值
            # max(nums[j] XOR x), nums[j]
            i = l
            p = head
            result = x >> (i+1)
            while i >= 0:
                t_x = x>>i & 1
                i -= 1
                if t_x == 0:
                    if p.right:
                        p = p.right
                        result = result*2+1
                    else:
                        p = p.left
                        result *= 2
                else:
                    if p.left:
                        p = p.left
                        result = result*2+1
                    else:
                        p = p.right
                        result *= 2
            return result
                        
        i = 0
        for item in index:
            # x,m: queries
            x, m = queries[item]
            while i<n and nums[i] <= m:
                insert(nums[i])
                i += 1
            if i == 0:
                answer[item] = -1 # 没有更小值,为-1
            else:
                answer[item] = search(x)
        return answer

131.分割回文串

  • 找字符串所有可能的回文子串分割方案(从头分到尾) ————后续题目:Ⅱ、Ⅲ、Ⅳ

递归
待改进: 存储重复结果,后续直接调用(dp)

class Solution:
    def partition(self, s: str) -> List[List[str]]:
        # 所有可能的回文串分割方案
        # length <= 16
        # 递归
        # F = {} DP没用上
        n = len(s)
        def is_pstring(s): # 判断是否为回文串
            if s == s[::-1]:
                return True
            else:
                return False
        
        def sub_partition(s, n, result): # 结果不断合并并传递到最底层直接返回
            if n == 1:
                return [result+[s]]
            if n == 0:
                return [result]
            temp = []
            for i in range(1, n+1):
                if is_pstring(s[:i]): # 提前结束, 判读不成立则不继续进行
                    t = sub_partition(s[i:],n-i,result+[s[:i]])
                    temp += t 
            return temp

        result = sub_partition(s,n,[])
        return result

664.奇怪的打印机

  • 每次在任意位置打印连续 同一字符,可覆盖。求最少打印次数。

DP:最少打印次数 F [ i , j ] F[i,j] F[i,j],起始位置 i i i,终点位置 j j j
F[i, j] = F[i+1,j-1]+1 if a[i]==a[j] else min(F[i,k]+F[k+1,j]) i<=k
F F F初始化为 1 1 1,顺序计算 [ F [ j , j + i ] j = 0 n − i ] i = 0 n [F[j,j+i]_{j=0}^{n-i}]_{i=0}^{n} [F[j,j+i]j=0ni]i=0n.

class Solution:
    def strangePrinter(self, s: str) -> int:
        # 最少打印次数
        n = len(s)
        MAX = float('inf')
        F = [[1]*n for _ in range(n)]
        for i in range(0,n):
            for j in range(0, n-i):
                # F(j, j+i)
                if s[j] == s[j+i]:
                    F[j][j+i] = F[j][j+i-1]
                else:
                    temp = MAX
                    for k in range(j,j+i):
                        temp = min(temp,F[j][k]+F[k+1][j+i])
                    F[j][j+i] = temp
        return F[0][n-1]

1190.反转每队括号间的子串


遇右括号时将栈内遇左括号前元素都取出并反转去掉括号放回栈内。
??反转操作有重复,简化?

class Solution:
    def reverseParentheses(self, s: str) -> str:
        # 逐层反转每对匹配括号中的字符串
        # 栈
        stack = []

        for i in range(len(s)):
            if s[i] == ')':
                temp = []
                while stack[-1] !='(':
                    temp.append(stack.pop())
                stack.pop()
                while temp:
                    stack.append(temp.pop(0))
            else:
                stack.append(s[i])
                
        return ''.join(stack) 

477.汉明距离总和

汉明距离:bin(a^b).count('1'),暴力穷举会超时。
按位统计所有数。

import numpy as np
class Solution:
    def totalHammingDistance(self, nums: List[int]) -> int:
        # 数组中任意两个数之间汉明距离的总和

        # def HammingDistance(a,b): # 计算汉明距离
        #     return bin(a^b).count('1')
        # # 暴力穷举结果时间超限O(n^2)
        # count = 0
        # for i in range(len(nums)):
        #     for j in range(i+1,len(nums)):
        #         count += HammingDistance(nums[i], nums[j])
        # return count

        
        n = len(nums)
        count = 0
        for i in range(30):
            temp = 0
            for j in range(n):
                temp += nums[j]>>i & 1 
            count += temp*(n-temp) # 统计所有数每一位中,1的个数*0的个数 = 该位汉明距离
        return count

234.2的幂

  • 判断是否是 2 的幂次方
    使用math.log(n,2),在n很大时会有很小的余数不能使用。
    使用n&(n-1) == 0 e . g . 1000 & 0111 = = 0 e.g.1000 \& 0111 == 0 e.g.1000&0111==0
class Solution:
    def isPowerOfTwo(self, n: int) -> bool:
        # 判断是否是 2 的幂次方
        # -2^31 <= n <= 2^31 - 1
        if n<=0:
            return False
        return n&(n-1) == 0  # 1000 & 0111 == 0

342.4的幂

  • 判断是否是4的幂次方

先判断是否是2的幂次方, n & ( n − 1 ) = = 0 n\&(n-1)==0 n&(n1)==0
4的幂次方有偶数个01在奇数位上

题解:

  1. m a s k = ( 10101010101010101010101010101010 ) 2 mask = (10101010101010101010101010101010)_2 mask=(10101010101010101010101010101010)2 m a s k & n = = 0 mask\&n==0 mask&n==00xaaaaaaaa = 0b10101010101010101010101010101010,0x:16进制,0b:2进制。
  2. n % 3 = = 1 n\%3==1 n%3==1
class Solution:
    def isPowerOfFour(self, n: int) -> bool:
        # 4:100; 16:10000; 64:1000,000; 偶数个0
        if n&(n-1)==0 and bin(n).count('0')%2==1: # num % 3 == 1
            return True
        else:
            return False

523.连续的子数组和

  • nums数组是否有连续子数组,元素总和为 k 的倍数(题目这里0是任何数的倍数)

前缀和+哈希表
一维数组 F [ i ] F[i] F[i] 存储 0 0 0 ~ i i i 的和。

 class Solution:
    def checkSubarraySum(self, nums: List[int], k: int) -> bool:
        # 是否有连续子数组元素总和为 k 的倍数
        n = len(nums)
        F = [0]*n

        # 初始化
        F[0] = nums[0]
        for i in range(1,n):
            F[i] = F[i-1]+nums[i]
            if F[i]%k==0:
                return True

        for i in range(1,n):
            temp = F[i]
            if temp > k:
                for j in range(1,i):
                    temp = F[i]-F[j-1] # i~j:F[i]-F[j-1]
                    if temp<k:
                        break
                    elif temp%k == 0:
                        return True
        
        # 0*x = 0情况
        temp = 0
        for i in range(0,n):
            if nums[i]==0:
                if temp == 1:
                    return True
                temp = 1
            else:
                temp = 0
        return False

525.连续数组

  • 相同数量的 0 和 1 的最长连续子数组

前缀和+哈希表,同523.连续的子数组和
遇0减1,遇1加1。相等值位置区间0、1数量相等。

class Solution:
   def findMaxLength(self, nums: List[int]) -> int:
       # 相同数量的 0 和 1 的最长连续子数组
       hashmap = {0:-1}
       n = len(nums)
       # F = [0]*(n+1)
       f = 0
       count = 0
       F[0] = 1 if nums[0]==1 else -1
       for i in range(0, n):
           if nums[i] == 0:
               # F[i] = F[i-1]-1 # '1'-'0'
               f -= 1
           else:
               # F[i] = F[i-1]+1
               f += 1
           if F[i] in hashmap:
               count = max(count, i-hashmap[f])
           else:
               hashmap[f] = i
       return count

160.相交链表

用俩list存储两个链表的各个节点,从尾部节点到首节点判断相等。

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

class Solution:
    def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
        # 两个单链表相交的起始节点
        p1,p2 = headA,headB
        list1 = []
        list2 = []
        while p1:
            list1.append(p1)
            p1 = p1.next
        while p2:
            list2.append(p2)
            p2 = p2.next
        
        if not (list1 and list2 and list1[-1]==list2[-1]):
            return None

        while list1 and list2 and list1[-1]==list2[-1]:
            list1.pop()
            list2.pop()
            pass
        if list1:
            return list1[-1].next
        else:
            return headA

474.一和零

背包问题
方法一:

  • 字典 hash_map[x,y] = z 表示 x 个0 y 个1最大子集的大小为 z .
  • 对于strs中每个字符串都遍历更新字典。

方法二:

  • 动态规划:三维 dp[i][j][k] 表示在前 i 个字符串中,使用 j 个 0 和 k 个 1 的情况下最多可以得到的字符串数量。
  • d p [ k ] [ i ] [ j ] = d p [ i − 1 ] [ j ] [ k ] ; i < z e r o s  and  j < o n e s . dp[k][i][j] = dp[i−1][j][k]; idp[k][i][j]=dp[i1][j][k];i<zeros and j<ones.
  • d p [ i ] [ j ] [ k ] = m a x ( d p [ i − 1 ] [ j ] [ k ] , d p [ i − 1 ] [ j − z e r o s ] [ k − o n e s ] + 1 ) ; i < z e r o s  or  j < o n e s . dp[i][j][k] = max(dp[i−1][j][k],dp[i−1][j−zeros][k−ones]+1); idp[i][j][k]=max(dp[i1][j][k],dp[i1][jzeros][kones]+1);i<zeros or j<ones.
# 方法一
import copy
class Solution:
    def findMaxForm(self, strs: List[str], m: int, n: int) -> int:
        # strs 的最大子集的大小,最多有 m 个 0 和 n 个 1
        
        def count(s): 
        # return 字符串s中 0 和 1 的个数
            count = 0
            n = len(s)
            for i in range(n):
                if s[i] == '0':
                    count += 1
            return count, n-count
		
		hash_map = {}
        for s in strs:
            x,y = count(s)
            for key, val in hash_map.copy().items():
                (key_0, key_1) = key
                k0, k1 = key_0 + x, key_1 + y
                if k0 <= m and k1 <= n:
                    hash_map[k0, k1] = max(hash_map.get((k0, k1),0), 1+val)  # 更新字典
            if x<=m and y<=n:
                hash_map[x, y] = hash_map.get((x, y), 1) # 添加当前值

        if hash_map:
            return max(hash_map.values())
        else:
            return 0

494.目标和

  1. list存储结果:超时
import numpy as np
class Solution:
    def findTargetSumWays(self, nums: List[int], target: int) -> int:
        # 构造表达式=target个数, 只能+或-
        c = nums.count(0)
        while 0 in nums:
            nums.remove(0)
        n = len(nums)

        count = np.zeros(2**n)
        for i in range(n):
            m = 2**i
            for j in range(m):
                count[j+m] = count[j]-nums[i]
                count[j] += nums[i]
        return int(np.sum(count == target))*2**c
  1. 递归,超时
import numpy as np
class Solution:
    def findTargetSumWays(self, nums: List[int], target: int) -> int:
        # 构造表达式=target个数, 只能+或-
		# 递归
        if len(nums) == 1:
            count = 0
            if nums[0] == target:
                count += 1
            if nums[0] == -1*target:
                count += 1 
            return count

        return self.findTargetSumWays(nums[1:],target+nums[0]) + self.findTargetSumWays(nums[1:],target-nums[0])
  1. DP,规律: 能用递归解决的都能用动态规划解决?
    d p [ i ] [ j ] = d p [ i − 1 ] [ j − n u m s [ i ] ] + d p [ i − 1 ] [ j + n u m s [ i ] ] dp[i][j] = dp[i-1][j-nums[i]]+dp[i-1][j+nums[i]] dp[i][j]=dp[i1][jnums[i]]+dp[i1][j+nums[i]] or
    d p [ i ] [ ( j − 1 ) + n u m s [ j ] ] = d p [ i − 1 ] [ j − 1 ] dp[i][(j-1)+nums[j]] = dp[i-1][j-1] dp[i][(j1)+nums[j]]=dp[i1][j1], d p [ i ] [ ( j + 1 ) + n u m s [ j ] ] = d p [ i − 1 ] [ j − 1 ] dp[i][(j+1)+nums[j]] = dp[i-1][j-1] dp[i][(j+1)+nums[j]]=dp[i1][j1]
    存储结构想了很久,稀疏矩阵 → \rightarrow 最终采用字典列表e.g.[{}{}]
import numpy as np
class Solution:
    def findTargetSumWays(self, nums: List[int], target: int) -> int:
        # DP
        # dp[i][j], 0~i:nums, target:j
        # dp[i][j] = dp[i][j+nums[0]]+dp[i][j-nums[0]]
        n = len(nums)
        m = 2**n
        dp = [{} for _ in range(n)]
        dp[0][nums[0]] = dp[0].get(nums[0], 0)+1
        dp[0][-nums[0]] = dp[0].get(-nums[0], 0)+1
        for i in range(1, n):
            for tar,val in dp[i-1].items():
                dp[i][tar+nums[i]] = dp[i].get(tar+nums[i], 0) + val
                dp[i][tar-nums[i]] = dp[i].get(tar-nums[i], 0) + val
        if dp[n-1].get(target):
            return dp[n-1][target]
        else:
            return 0

879.盈利计划

  • 方法1:
    F[i,j] = k,员工i人,利润j,方案个数k
    每增加一个工作,原F不变,更新: F [ i + g r o u p [ i ] , j + p r o f i t [ i ] ] + = k F[i+group[i], j+profit[i]] += k F[i+group[i],j+profit[i]]+=k
    最后需要遍历F找>minProfit个数。
  • 方法2:DP
# Plan 1
import copy
class Solution:
    def profitableSchemes(self, n: int, minProfit: int, group: List[int], profit: List[int]) -> int:
        # 至少产生 minProfit 利润的子集,计划数
        m = len(group)
        F = {(0,0):1}
        if group[0]<=n:
            F[group[0], profit[0]] = 1
            
        for i in range(1,m):
            for (peo,pro), plans in F.copy().items():
                if peo+group[i] <= n:
                    F[peo+group[i], pro+profit[i]] = F.get((peo+group[i], pro+profit[i]), 0) + plans

        mod = 10**9 + 7
        count = 0
        for (_,pro), plans in F.items():
            if pro >= minProfit:
                count+=plans
        return count%mod

518.零钱兑换

DP F [ i ] = ∑ c o i n F [ i − c o i n ] F[i] = \sum^{coin} F[i-coin] F[i]=coinF[icoin]

  • coins: 各硬币分值,求组成 amount 有几种方案。

注意循环顺序,不要重复计算:

  • 如果先遍历 coins 再遍历 i~amount 会有重复计算(eg.3(2(1+1)+1, 1+1+1))。
  • 所以先遍历 i~amount 再遍历 coins
class Solution:
    def change(self, amount: int, coins: List[int]) -> int:
        # 凑成总金额的硬币组合数
        # F[n] = sum(F[n-coins[i]])
        F = [0] * (amount+1)
        F[0] = 1
        for coin in coins:
            for i in range(coin,amount+1):
                F[i] += F[i-coin]
        return F[amount]

279.完全平方数

DP :方法类似于:518.零钱兑换
F [ i ] = m i n ( F [ i − n u m ] ) + 1 F[i] = min(F[i-num])+1 F[i]=min(F[inum])+1, n u m num num为平方数

class Solution:
    def numSquares(self, n: int) -> int:
        # 最小个数的完全平方数和等于n
        # F[i] = min(F[i-num])+1, num某平方数
        F = [float('inf')]*(n+1)
        F[0] = 0 # 初始值
        i = 1
        while i*i<=n:
            temp = i*i
            for j in range(temp,n+1):
                F[j] = min(F[j], F[j-temp]+1)
            i+=1
        return F[n]

877.石子游戏

  • 题目描述:奇数个石子,分为一行偶数堆。每次只能拿两端的一堆。Alex先拿,若赢返回True。

DP: d p [ i ] [ j ] dp[i][j] dp[i][j]为从第i堆到第j堆,当前玩家与另一个玩家的石子数量之差的最大值。
d p [ i ] [ j ] = m a x ( p i l e s [ i ] − d p [ i + 1 ] [ j ] , p i l e s [ j ] − d p [ i ] [ j − 1 ] ) dp[i][j] = max(piles[i]-dp[i+1][j], piles[j]-dp[i][j-1]) dp[i][j]=max(piles[i]dp[i+1][j],piles[j]dp[i][j1])
即:当前玩家拿了的一堆 -(另一个玩家 - 未拿当前玩家)= 当前玩家 - 另一个玩家

其实return True # Alex总是赢. 若存在li能赢的情况,则Alex总可以选择li的那种拿法也总是能赢。

class Solution:
    def stoneGame(self, piles: List[int]) -> bool:
        # 总数奇数,偶数堆,石子最多的玩家获胜
        n = len(piles)
        dp = [[0]*n for _ in range(n)]
        for i in range(n):
            dp[i][i] = piles[i]
        for i in range(1,n):
            for j in range(n-i):
                dp[j][j+i] = max(piles[j]-dp[j+1][j+i], piles[j+i]-dp[j][j+i-1])
        return dp[0][n-1]>0

401.二进制手表

  • 已知亮灯数目turnedOn,求所有可能表示的时间。
  • 时针4位(0-11),秒针6位(0-59)
  • 递归
class Solution:
    def readBinaryWatch(self, turnedOn: int) -> List[str]:
        # 当前亮着的 LED 的数量, 返回二进制手表可以表示的所有可能时间
        def Binary(count, total, current): 
            """
            统计当前计数list并返回
	            count:亮灯数
	            total:总灯数
	            current:当前计数
            """
            if count == 0:
                return [current]
            elif total == 0:
                return []
            temp = []
            current *= 2
            for i in range(total-count+1):
                temp += Binary(count-1, total-i-1, (current+1)*2**i)
            return temp

        save = []
        for i in range(max(0,turnedOn-6),min(4,turnedOn+1)):
            save1 = Binary(i, 4, 0)
            save2 = Binary(turnedOn-i, 6, 0)
            for s1 in save1:
                for s2 in save2:
                    if s1<=11 and s2<=59:
                        save.append('{}:'.format(s1)+"%02d" % s2)
        return save

38.字符串的排序

  • 题目描述:打印出字符串所有的字符排列
  • 回溯:递归
  • result列表去重:list(set(result))注:set() 无序不重复元素集
class Solution:
    def permutation(self, s: str) -> List[str]:
        # 打印出该字符串中字符的所有排列
        if len(s)==1: # 终止条件
            return [s]
        result = []
        for i in range(len(s)): 
        # 每次固定列表中一个位(s[i])为首位, 递归得到剩下结果 t
            result += [s[i]+t for t in self.permutation(s[0:i]+s[i+1:])]
        return list(set(result)) # 去重

149.直线上最多的点数

  • 题目:给所有点坐标,算最多有多少个点在同一条直线上。

算所有两点间的直线。

from fractions import Fraction
class Solution:
    def maxPoints(self, points: List[List[int]]) -> int:
        # 该方法有重复,暴力
        points.sort() # 排序

        n = len(points)
        line = [{} for _ in range(n-1)]
        for i in range(n):
            for j in range(i+1,n):
                # i,j两点确定直线 y = kx + b
                if points[j][0] == points[i][0]:
                    k,b = 0, points[j][0]
                else:
                    k = Fraction(points[j][1]-points[i][1], points[j][0]-points[i][0]) # 分数表示
                    b = points[j][1] - k*points[j][0]
                line[i][k,b] = line[i].get((k,b), 1) + 1
        temp = 1
        for i in range(n-1):
            temp = max(list(line[i].values())+[temp])
        return temp

168.Excel表列名称

  • 题目:返回正整数在 Excel 表中相对应的列名称(类似进制表示)
class Solution:
    def convertToTitle(self, columnNumber: int) -> str:
        # 返回正整数在 Excel 表中相对应的列名称
        # 1~26:A~Z (每位1~26; 每位权重:26^2, 26, 1)
        result = ''

        while columnNumber:
        	# 题解:
            # a0 = (columnNumber - 1) % 26 + 1  # 取1~26位
            # result = chr(a0 - 1 + ord("A")) + result  # 1~26位字符
            # columnNumber = (columnNumber - a0) / 26
            
            if columnNumber % 26 == 0: # 单独判断26
                result = chr(ord("Z"))+result
                columnNumber -= 26
            else:
                result = chr(ord("@") + columnNumber%26) + result # 1~25:取26余数
            columnNumber //= 26  # 整除26
        return result

LCP07.传递信息

广度优先搜索
其余方法:深度优先搜索,dp

class Solution:
    def numWays(self, n: int, relation: List[List[int]], k: int) -> int:
        # 方案数: k次从0~(n-1)
        save = {}
        for r in relation:
            save[r[0]] = save.get(r[0], [])
            save[r[0]].append(r[1])

        present = [0]
        for i in range(k):
            temp = []
            for l in present:
                if save.get(l):
                    temp.extend(save[l])
            present = temp
        count = 0
        for i in present:
            if i == n-1:
                count += 1
        return count

1833.雪糕的最大数量

排序+贪心

class Solution:
    def maxIceCream(self, costs: List[int], coins: int) -> int:
        # 雪糕的最大数量,价格数组 costs 和现金量 coins
        # 贪心,选最小
        costs.sort()
        i = 0
        while i<len(costs) and costs[i] <= coins:
                coins -= costs[i]
                i += 1
        return i

726.原子的数量

非右括号入栈,遇右括号把前面最后一个左括号之后的出现次数都乘括号后的数,去掉左括号。循环到字符串尾部。
栈内元素加入字典,排序,变字符串输出。

class Solution:
    def countOfAtoms(self, formula: str) -> str:
        result = {}
        n = len(formula)
        i = 0
        stack = []
        while i < n:
            if formula[i] == '(':
                stack.append([formula[i], 1])
                i += 1
            elif formula[i] == ')':
                # num = int(formula[i+1])
                num = 0
                j = i + 1
                while j<n and '0'<=formula[j]<='9': # 数字
                    num = num*10 + int(formula[j])
                    j += 1
                if not num:
                    num = 1
                i = j
                j = -1
                while stack[j][0] != '(':
                    stack[j][1] *= num
                    j -= 1
                stack.pop(j)
            else:
                if i+1<n and 'a'<=formula[i+1]<='z': # 小写字母
                    count = 0
                    j = i + 2
                    while j<n and '0'<=formula[j]<='9': # 数字
                        count = count*10 + int(formula[j])
                        j += 1
                    if not count:
                        count = 1
                    stack.append([formula[i:i+2], count])
                    i = j
                else:
                    count = 0
                    j = i + 1
                    while j<n and '0'<=formula[j]<='9': # 数字
                        count = count*10 + int(formula[j])
                        j += 1
                    if not count:
                        count = 1
                    stack.append([formula[i], count])
                    i = j

        while stack:
            p = stack.pop()
            result[p[0]] = result.get(p[0], 0) + p[1]
                    
        temp = ''
        for key, val in sorted(result.items()):
            temp += key
            if val > 1:
                temp += str(val)
        return temp

1711.大餐计数

  • 求大餐的数量,大餐:恰好包含两道不同餐品,美味程度之和等于 2 的幂。

暴力会超时
0 < = d e l i c i o u s n e s s [ i ] < = 2 20 0 <= deliciousness[i] <= 2^{20} 0<=deliciousness[i]<=220
哈希表,穷举幂指数,若 2 n − d e l i c i o u s n e s s [ i ] ∈ d e l i c i o u s n e s s [ 0 : n ] 2^n-deliciousness[i] \in deliciousness[0:n] 2ndeliciousness[i]deliciousness[0:n],则计数加一。

import math
class Solution:
    def countPairs(self, deliciousness: List[int]) -> int:
        count = 0
        MOD = 10**9 + 7
        n = len(deliciousness)
        de = {}
        maximum = max(deliciousness)
        m = int(math.log(2*maximum,2)) + 1
        for i in range(n):
            temp = 0 if not deliciousness[i] else int(math.log(deliciousness[i], 2))
            for j in range(temp, m): # m->22
                if 2**j - deliciousness[i] in de:
                    count += de[2**j - deliciousness[i]]
            de[deliciousness[i]] = de.get(deliciousness[i] ,0) + 1
            count %= MOD
        return count % MOD

930.和相同的二元子数组

  • 和为 goal 的 非空 子数组 (连续) 个数, nums[i] 不是 0 就是 1

方法一:F为按位统计和,超时

class Solution:
    def numSubarraysWithSum(self, nums: List[int], goal: int) -> int:
		n = len(nums)
        F = [0]*(n+1)
        F[0] = nums[0]
        count = 0
        for i in range(1, n):
            F[i] = F[i-1] + nums[i]
        
        for i in range(n):
            if F[i] >= goal:
                j = -1
                while F[i]-F[j] > goal:
                    j += 1
                while j < i and F[i]-F[j] == goal:
                    print(i, j)
                    j += 1
                    count += 1
        return count

方法二:用哈希表记录每一种前缀和出现的次数,假设我们当前枚举到元素 nums [ j ] \textit{nums}[j] nums[j],我们只需要查询哈希表中元素 sum [ j ] − goal \textit{sum}[j]-\textit{goal} sum[j]goal 的数量。
来源:这里

方法三:考虑 nums[i] 不是 0 就是 1,记录1的位置

class Solution:
    def numSubarraysWithSum(self, nums: List[int], goal: int) -> int:
        # 和为 goal 的 非空 子数组(连续)个数, nums[i] 不是 0 就是 1
        n = len(nums)
        count = 0
		
		# F[i] = j: 第i个1下标为j
		# F[0] = -1, F[-1] = n
        F = [-1]
        for i in range(n):
            if nums[i] == 1:
                F.append(i)
        F.append(n) 

        if goal == 0: # 目标0单独计算,累加
            for i in range(1, len(F)):
                # 累加 F[i]-F[i-1]
                count += sum(range(1, F[i]-F[i-1]))
            return count

        for i in range(goal, len(F)-1):
                j = i - goal + 1
                count += (F[j] - F[j-1]) * (F[i+1] - F[i]) # 两边0个数*
        return count

981.基于时间的键值存储

哈希表+二分查找

class TimeMap:

    def __init__(self):
        """
        Initialize your data structure here.
        """
        self.time_map = defaultdict(list)


    def set(self, key: str, value: str, timestamp: int) -> None:
    	# 输入已经是升序排列
        self.time_map[key].append([value, timestamp])


    def get(self, key: str, timestamp: int) -> str:
        # 二分查找,不大于timestamp的最大值
        data = self.time_map[key]
        left = 0
        right = len(data) - 1
        while left <= right:
            mid = (left + right) // 2
            if data[mid][1] == timestamp:
                right = mid
                break
            elif data[mid][1] > timestamp:
                right = mid - 1
            else:
                left = mid + 1
        return data[right][0] if right>=0 else ""

274.H的指数

共有 h 篇论文分别被引用了至少 h 次, 其余的 N - h 篇论文每篇被引用次数 不超过 h 次

class Solution:
    def hIndex(self, citations: List[int]) -> int:
        citations.sort(reverse=True) # 排序
        
        n = len(citations)
        if not n or citations[0] < 1:
            return 0
        elif n == 1:
            return 1

        for i in range(1, n):
            if citations[i] <= i:
               return i
        return n

275.H指数Ⅱ

class Solution:
    def hIndex(self, citations: List[int]) -> int:
        if not citations: # 空情况
            return 0
        n = len(citations)
        i = 1
        while i <= n and citations[n-i] >= i: # 只要第i个位置数>=i才考虑下一位
            i += 1
        return i-1

218.天际线问题⭐⭐

思路:参考☞这里

  • 已知:
    建筑物信息由三元组构成: (左边缘坐标,右边缘坐标,高度)
    天际线关键点为 (坐标,变化后高度)
    建筑物已经按照左边缘坐标排好序了,求关键点坐标列表。
  • 思路:
    按坐标顺序将 (坐标,高度) 加入列表,并排序:坐标递增高度递增。
    遍历列表,遇到左边缘坐标,就将高度递增插入高度列表中,遇到右边缘删除该信息。
    若在过程中,最大高度发生变化,则为关键点。
class Solution:
    def getSkyline(self, buildings: List[List[int]]) -> List[List[int]]:
        heights = [] # (坐标,高度)列表
        for left, right, h in buildings:
            heights.append([left, -h])
            heights.append([right, h])
        heights.sort(key=lambda x:(x[0], x[1])) # 坐标递增高度递增

        points = []
        hightest = [0]
        for pos, h in heights:
            if h < 0: # 增加
                i = 0
                n = len(hightest)
                while i<n and -h<=hightest[i]:
                    i += 1
                hightest.insert(i, -h)
                # 高度增高
                if i == 0:
                    points.append([pos, hightest[0]])
            else: # 删除
            	# 二分查找
                left, right = 0, len(hightest)-1
                while left <= right:
                    mid = (left + right) // 2
                    if hightest[mid] == h:
                        del(hightest[mid])
                        break
                    elif hightest[mid] < h:
                        right = mid - 1
                    else:
                        left = mid + 1
                # 高度降低
                if hightest[0] < h:
                    points.append([pos, hightest[0]])
        return points

1818.绝对差值和

import numpy as np
class Solution:
    def minAbsoluteSumDiff(self, nums1: List[int], nums2: List[int]) -> int:
        n = len(nums1)
        total = [0]*n
        count = 0
        MOD = 10**9 + 7

        for i in range(n):
            total[i] = abs(nums1[i]-nums2[i])
        index = np.argsort(np.array(total)) # 排序下标从小到大

        for i in index[::-1]: #从大到小
            if count >= total[i]: # 提前终止条件
                break
            for j in range(n):
                if i != j:
                    count = max(count, total[i] - abs(nums2[i]-nums1[j])) # 保留最大的数
        return (sum(total) - count)% MOD

1931.用三种不同颜色为网格涂色⭐❓

图的问题


面试题10.02.变位词组

class Solution:
    def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
        n = len(strs)
        dic = defaultdict(list)
        for word in strs:
            p = list(word)
            p.sort()
            dic[''.join(p)].append(word)
        return list(dic.values())

1838.最高频元素的频数

class Solution:
    def maxFrequency(self, nums: List[int], k: int) -> int:
        # 加一
        nums.sort()
        n = len(nums)
        frequency = 1 # 最大可能频数
        operand = 0 # 操作数

        # 滑动窗口
        for i in range(1, n):
            j = i - frequency # 窗口尾部,窗口大小为freauency
            operand += (nums[i]-nums[i-1]) * frequency # 当前窗口前端加一位之后的总操作数
            if operand > k: # 操作次数多了,不考虑更小窗口情况
                operand = operand - nums[i] + nums[j]
            else:
                frequency += 1
                while j > 0:
                    j -= 1 # 窗口尾部增长
                    operand += nums[i] - nums[j]
                    if operand > k:
                        operand -= nums[i] - nums[j]
                        break
                    frequency += 1
        return frequency

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

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

class Solution:
    def copyRandomList(self, head: 'Node') -> 'Node':
        if not head:
            return None
        save = {None:None} # node : new_node

        # 头节点
        new_head = Node(head.val)
        save[head] = new_head

        # 节点生成,next串起来
        p = new_head
        h = head.next
        while h:
            q = Node(h.val)
            save[h] = q
            p.next = q
            p = q
            h = h.next
        p.next = None

        # random串起来
        p = new_head
        while head:
            p.random = save[head.random]
            head = head.next
            p = p.next
        return new_head

1738.找出第K大的异或坐标值

class Solution:
    def kthLargestValue(self, matrix: List[List[int]], k: int) -> int:
        # 坐标(a,b) : matrix[i][j]异或得到(0<=i<=a ,0<=j<=b)
        m, n = len(matrix), len(matrix[0])
        dp = [0]*(n*(m+1))
        for i in range(m):
            count = 0
            for j in range(n):
                count ^= matrix[i][j]
                dp[i*n+j] = dp[(i-1)*n+j]^count
        dp.sort(reverse=True)
        return dp[k-1]

671.二叉树中第二小的节点

非空特殊的二叉树:每个节点的子节点数量只能为 2 或 0,节点的值等于两个子节点中较小的一个。
想法:第一小的节点根节点,若左右节点和根节点值相同则存起来(栈或者队列都行),否则比较最小值。
e.g. 第一小的值1,第二小的值2。
Code算法_第2张图片

class Solution:
    def findSecondMinimumValue(self, root: TreeNode) -> int:
        stack = [root]
        result = float('inf')
        while stack:
            p = stack.pop()
            if p.left:
                if p.left.val == p.val:  # 相等点入栈
                    stack.append(p.left)
                else:
                    result = min(result, p.left.val)  # 不等点找最小值

                if p.right.val == p.val:  # 相等点入栈
                    stack.append(p.right)
                else:
                    result = min(result, p.right.val)  # 不等点找最小值
        if result < float('inf'):
            return result
        else:
            return -1

987.二叉树的垂序遍历

class Solution:
    def verticalTraversal(self, root: TreeNode) -> List[List[int]]:
        stack = [[root,0,0]]
        save = defaultdict(list)

        while stack: # 层次遍历
            p = stack.pop(0)
            save[p[2]].append((p[1],p[0].val))
            if p[0].left:
                stack.append([p[0].left, p[1]+1, p[2]-1])
            if p[0].right:
                stack.append([p[0].right, p[1]+1, p[2]+1])
                
        result = []
        for key, val in sorted(save.items()): # 按列排序
            val.sort(key=lambda x:(x[0], x[1])) # 按行排序,相同行按值排序
            result.append([i for _,i in val])
        return result

611.有效三角形个数

class Solution:
    def triangleNumber(self, nums: List[int]) -> int:
        # 统计其中可以组成三角形三条边的三元组个数
        def binary(left, right, target):
            while left <= right:
                mid = (left + right)//2
                if nums[mid] < target:
                    left = mid+1
                else:
                    right = mid-1
            return right
        
        nums.sort()  # 排序
        n = len(nums)
        count = 0
        for i in range(n-2):
            for j in range(i+1, n-1):
                # 二分查找 从j+1~n-1:nums[i] + nums[j]
                count = count + binary(j+1, n-1, nums[i] + nums[j]) - j
        return count

847.访问所有节点的最短路径

参考:here

  1. 队列,广度优先搜索:先把所有图上所有节点入队列,存储格式(e.g.当前点i, 已访问所有节点10001, 所有访问次数1)
  2. set保存到每个节点的访问状态,防止重复计算,存储格式(e.g.当前点i, 已访问所有节点10001)实现O(1)查找
  3. 直到找到一个访问了所有点的路径,返回。
class Solution:
    def shortestPathLength(self, graph: List[List[int]]) -> int:
        # 能够访问所有节点的最短路径的长度——>类旅行商(TSP)问题
        # BFS
        # 状态压缩:用n位二进制数
        n = len(graph)
        stack = [[i, 1<<i, 0] for i in range(n)] # 队列,存储 (当前点, 已访问节点, 所有访问次数)
        state = {(i, 1<<i) for i in range(n)} # 时间复杂度O(1)

        while stack:
            p = stack.pop(0)
            if p[1] == 2 ** n - 1:
                return p[2]
            for next_point in graph[p[0]]:
                temp = p[1] | (1<<next_point)
                if (next_point, temp) not in state:
                    stack.append([next_point, temp, p[2]+1])
                    state.add((next_point, temp))
        return 0

516.最长回归子序列

求最长回归子序列长度,子序列可以不连续。
DP:
d p [ i ] [ j ] = d p [ i + 1 ] [ j − 1 ] , if  s [ i ] = s [ j ] ; dp[i][j] = dp[i+1][j-1],\text{if }s[i]=s[j]; dp[i][j]=dp[i+1][j1],if s[i]=s[j];
d p [ i ] [ j ] = m a x ( d p [ i ] [ j − 1 ] , d p [ i + 1 ] [ j ] ) , otherwise . dp[i][j] = max(dp[i][j-1], dp[i+1][j]),\text{otherwise}. dp[i][j]=max(dp[i][j1],dp[i+1][j]),otherwise.

class Solution:
    def longestPalindromeSubseq(self, s: str) -> int:
        n = len(s)
        dp = [[0]*n for _ in range(n)]
        for i in range(n):
            dp[i][i] = 1

        for i in range(1, n):
            for j in range(n-i):
                x,y = j, i+j
                if s[x] == s[y]:
                    dp[x][y] = dp[x+1][y-1] + 2
                else:
                    dp[x][y] = max(dp[x][y-1], dp[x+1][y])

        return dp[0][n-1]

470.用Rand7()实现Rand10()

题解:这里


318.最大单词长度乘积

class Solution:
    def maxProduct(self, words: List[str]) -> int:
        # 不含有公共字母两个单词长度相乘的最大值
        words_set = [set(i) for i in words]
        n = len(words_set)
        flag = 0
        for i in range(n):
            for j in range(i+1,n):
                temp = 0
                for k in words_set[i]:
                    if k in words_set[j]:
                        temp = 1
                        break
                if temp == 0:
                    flag = max(flag, len(words[i]*len(words[j])))
        return flag

python

内部函数(函数内函数)能访问函数外函数不能直接修改函数外变量。
若需要修改则需要加关键字nonlocal,若加关键字global只能覆盖原内容。

面向对象编程

  • 封装、继承、多态
  • 类、实例

内置函数来自☛这里
Code算法_第3张图片
数学:

  • math.log(n, 2) : l o g 2 n log^n_2 log2n

键盘/文件 → \rightarrow 读入/读出:

  • 读入input()
a = int(input()) # input()
b = [int(i) for i in input().split()] # input().split()
import sys
a = sys.stdin.readline() # 读一行
b = a.split() # 空格分割
# 一直输入
import sys
for line in sys.stdin:
    b = line.split()
n = int(sys.stdin.readline().strip())
for i in range(n):
    line = sys.stdin.readline().strip()  # strip()去除首尾空格
    values = list(map(int, line.split()))
  • 文件
    • read(), readline(), readlines()
    • write(), writelines()
    • truncate()字符串截取??
    • open(), close()
    • wrax()??

常用:

  • None没有Null(python)
  • MAX = float('inf') 无穷大
  • 分数表示:防止小数不整除导致的余数不等情况
from fractions import Fraction
	Fraction(4,5)

集合

  • set() 无序不重复元素集
  • &交、|并、-差、^
  • [[i, 1<, set内部是dict实现的,O(1)查找时间复杂度

字典:dict = {key: value}
defaultdict(default_factory)在访问当前不存在字典的key时,自动构建key : value (value类型是default_factory)default_factoryint, list

  • 创建:dict(zip('abc', [1, 2, 3]))

  • 操作:

    • remove, update, add, clear, discard, pop
    • issubset是否是子集,issuperset是否父集,取并、交、差集……
  • 添加:dict[key]=value,查找:dict[key] or dict.get(key[, default])

  • 取键值对dict.items()dict.values()dict.keys().

  • 字典生成式:{key : value for key, value in my_dictionary.items() if value > 10}

  • 注意:

    • 无序,不能按下标操作。
    • list 和 dict 类型是 unhashable,不可作为key

列表:list:[]

  • 表头插入list.append(num),表尾取出list.pop()
  • 列表合并:+ 或者 list.extend(list2)
  • 排序:list.sort(reverse=True) True: 大到小
  • list(range(i,j))生成 i 到 j 递增列表
  • list(map(int,列表名))将列表中数据都变成int类型

数据类型转换:

  • ord(ch) ASCII
  • 元组转列表list()
  • 转二进制bin()
  • 二进制转字符chr()
  • list 转 string:''.join(stack)''内是连接符
  • int(),set(), dict(), complex,list(), float()

你可能感兴趣的:(算法,python)