目前用到的算法:递归,双指针,动态规划,回溯法,贪心算法,滚动哈希,快速幂,滑动窗口,单调栈(哨兵),随机化,Boyer-Moore 投票算法,并查集,拓扑排序(dfs,bfs),Trie(前缀树)(二进制表示,高位为0左子树,为1右子树),快速排序,归并排序,堆排序,图dfs(邻接表,字典map),floyd,桶排序,基数排序,差分数组前缀和,状态压缩dp
取巧:链表题可用数组存储所有数,操作后,再新建链表返回
- 滑动窗口中位数 (双优先队列 + 延迟删除)
https://leetcode-cn.com/problems/sliding-window-median/solution/hua-dong-chuang-kou-zhong-wei-shu-by-lee-7ai6/
求最大值的最小值(最小值的最大值)通常使用二分法
k / x 上取整 == (k + x - 1)/ x下取整
Java:
// 位运算:
x & 1 // 判断末尾是否为1(判断奇偶性)
x | (1 << k) // 第k + 1位赋值为1
x ^ (1 << k) // 第k + 1位取反
(x >> k) & 1 // 判断x第k + 1位是否为1
x ^ (x + 1) // 取右边连续的1
x & (-x), -x = (~x + 1) // 取最低位1的位置 (负数补码为,源码取反+1(符号位不变))
一个数和0做XOR运算等于本身:a⊕0 = a
一个数和其本身做XOR运算等于 0:a⊕a = 0
XOR 运算满足交换律和结合律:a⊕b⊕a = (a⊕a)⊕b = 0⊕b = b
a ⊕ b = c -> a = b ⊕ c
// 枚举子集
// 考虑S的子集,在二进制上从大到小排成一排,那么大的通过减若干个1就一定能到小的,但是中间会产生大量的状态,这些状态中包含了一些S中不包含的1,故和S与一下,去冗即可.从而每两个相邻的状态就都是S的子集,由于降序从而任意两个状态不重复,即任意子集状态均可达
for (int sub = mask; sub; sub = (sub - 1) & mask) { }
一维前缀和:sum[i] = sum[i-1] + a[i]
二维前缀和:sum[i][j] = sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+a[i][j]
最大公约数 辗转相除法
public int gcd(int a, int b) {
return b == 0 ? a : gcd(b, a % b);
}
堆排序:n个节点,第i+1个节点,i节点的孩子:2*i+1, 2*i+2;节点的父亲(i-1)/2
xi
n = n & (n - 1) # n的二进制数,最后一位1变成0 // Pop count,或 汉明权重
如何获取二进制中最右边的 1:x & (-x)。
如何将二进制中最右边的 1 设置为 0:x & (x - 1)。
Manacher算法详解
https://www.cnblogs.com/cloudplankroader/p/10988844.html
https://leetcode-cn.com/problems/palindromic-substrings/solution/hui-wen-zi-chuan-by-leetcode-solution/
0x3f3f3f3f作为无穷大,小于32位int,作加法时不会溢出(当题目中范围明确不超过时可选)
二分查找中,mid = (left + right) / 2; 如果使用的编程语言会有整数溢出的情况(例如 C++,Java),则mid = left + (right - left) / 2
https://leetcode-cn.com/problems/candy/solution/fen-fa-tang-guo-by-leetcode/
方法 2:用两个数组 ?????????
https://leetcode-cn.com/problems/single-number-ii/solution/zhi-chu-xian-yi-ci-de-shu-zi-ii-by-leetcode/
方法三:位运算符:NOT,AND 和 XOR ???????(137. 只出现一次的数字 II)
Morris 遍历???? https://leetcode-cn.com/problems/binary-tree-preorder-traversal/solution/er-cha-shu-de-qian-xu-bian-li-by-leetcode-solution/
区间dp:1690. 石子游戏 VII (枚举区间)
基数排序:https://leetcode-cn.com/problems/maximum-gap/solution/xiang-xi-tong-su-de-si-lu-fen-xi-duo-jie-fa-by–39/
一维数组优化???:https://leetcode-cn.com/problems/maximum-gap/solution/zui-da-jian-ju-by-leetcode-solution/
计数质数:厄拉多塞筛法,线性筛
差分数组(1674. 使数组互补的最少操作次数):https://leetcode-cn.com/problems/minimum-moves-to-make-array-complementary/solution/jie-zhe-ge-wen-ti-xue-xi-yi-xia-chai-fen-shu-zu-on/
Python:
# 字符串转换整数 (atoi)
class Solution:
def myAtoi(self, str: str) -> int:
return max(min(int(*re.findall('^[\+\-]?\d+', str.lstrip())), 2 ** 31 - 1), -2 ** 31)
# re.findall(): 返回匹配的字符串列表,lstrip(): 删除字符串前面空格或其他字符。
a=['h','e','l','l','o'],则可以使用''.join(a)将它转为字符串。
a = set('hello, world')
{'e', 'd', 'r', 'w', ' ', 'h', 'o', 'l', ','} # 集合本身无序
a.add() # 添加元素不安顺序,
math.factorial() # 阶乘
@lru_cache(None) # 缓存修饰器
# 根据参数缓存每次函数调用结果,对于相同参数的,无需重新函数计算,直接返回之前缓存的返回值
any(iterable)
# 如果都为空、0、false,则返回false,如果不都为空、0、false,则返回true。
all(iterable)
# 如果iterable的所有元素不为0、''、False或者iterable为空,all(iterable)返回True,否则返回False;
from collections import Counter
colors = ['red', 'blue', 'red', 'green', 'blue', 'blue']
c = Counter(colors)
print (dict(c))
{'red': 2, 'blue': 3, 'green': 1}
# 字符串翻转:
nums = nums[::-1] ×
nums[:] = nums[::-1] √
nums.reverse() √
rows = [{} for i in range(9)]
rows[0]['5'] = 1
[{'5': 1}, {}, {}, {}, {}, {}, {}, {}, {}]
rows = [{}] * 9
rows[0]['5'] = 1
[{'5': 1}, {'5': 1}, {'5': 1}, {'5': 1}, {'5': 1}, {'5': 1}, {'5': 1}, {'5': 1}, {'5': 1}]
dict.get(num, 0) # 返回字典中键为num的值,不存在返回默认值0
from collections import defaultdict
d = defaultdict(int)
d['a'] += 1 # 不存在'a',则直接初始化d['a'] = 0
-> defaultdict(<class 'int'>, {'a': 1})
(1)list、set、dict:是不可哈希的
(2)int、float、str、tuple:是可以哈希的
ans = collections.defaultdict(list)
s = 'acb'
ans[tuple(sorted(s))].append(s) √
ans[sorted(s)].append(s) ×
# 交换nums[i], nums[nums[i] - 1]两个值
nums[i], nums[nums[i] - 1] = nums[nums[i] - 1], nums[i] # 错误,因为nums[i]先改变,nums[nums[i] - 1]的下标nums[i] - 1已改变
nums[nums[i] - 1], nums[i] = nums[i], nums[nums[i] - 1] # 正确
直接赋值:其实就是对象的引用(别名)。
a = [[1,2],[3,4]]
b = a.copy() # a改变,b跟着改变
拷贝父对象,不会拷贝对象的内部的子对象。(浅拷贝)
copy 模块的 deepcopy 方法,拷贝了父对象及其子对象。(深拷贝(deepcopy))
# 给两个二进制字符串,返回它们的和(用二进制表示)。
class Solution:
def addBinary(self, a, b) -> str:
# 字符串格式化输出
return '{0:b}'.format(int(a, 2) + int(b, 2))
str.ljust(width[, fillchar])
str.rjust(width[, fillchar])
# 返回一个原字符串左对齐(右对齐),并使用空格填充至指定长度的新字符串。如果指定的长度小于原字符串的长度则返回原字符串。
str = "this is string example....wow!!!";
print str.ljust(50, '0');
-> this is string example....wow!!!000000000000000000
# 正负无穷
float("inf"), float("-inf")
生成从 0..00 到 1..11 的所有 n 位掩码。生成固定长度的位掩码:例如 001,而不是 1。因此可以使用一些位操作技巧:
1. 位操作
nth_bit = 1 << n
for i in range(2**n):
# generate bitmask, from 0..00 to 1..11
bitmask = bin(i | nth_bit)[3:]
# 0b1000[3:] -> 000
2. 简单低效的迭代
for i in range(2**n, 2**(n + 1)):
# generate bitmask, from 0..00 to 1..11
bitmask = bin(i)[3:]
dp = [[False] * 2 for _ in range(2)] # 正确
dp = [[False] * 2] * 2]
# 错误, 改变一个值,都改变:
dp[0][1] = True -> dp = [[False, True], [False, True]]
from collections import deque
q = deque([1,2])
q.append(3)
q.popleft()
q.pop()
str.isalnum() Python isalnum() # 方法检测字符串是否由字母和数字组成。
str.lower() str.upper() # 大小写转换
str.isalpha() str.isdigit() # 判断是否是字母, 数字