算法小技巧

Posted by Liao on 2025-07-06

一、链表

如果遇到需要删除头节点的题目,添加哨兵节点可以简化代码逻辑,请记住这个技巧。 –灵神

  • 头节点会被删除的话,需要建立dummyNode
  • 反转链表有个很重要的性质:pre指向反转后这一段的末尾,cur指向这一段的下一个节点

二、双指针

  • 三数之和:如果数组有序,可以使用双向双指针

三、字符串、字符映射技巧

  • 代码实现时,可以创建一个哈希表(或者数组),把字符作为 key,对应的数值作为 value,从而避免写一堆if-else。
  • 代码实现时,由于 T 和 F 的 ASCII 值除以 2 后的奇偶性不同,也就是它们二进制的次低位不同,可以改为统计二进制次低位。
  • 如果字符串只包含小写字母或者大写字母,即只有26个,可以用[26]int{}数组代替map; 如果只包含空格、字符、数字(ASCII都是在128之内的),可以用[128]int{}代替map
  • 对于二进制,做法类似,往110的右边添加1,得到1101,做法是110*2+1=1101,或者110<<1 ∣ 1=1101
  • 异或就象消消乐,2个相同就消除了。

统一从0开始

1
2
字符->数字 c-‘a’
数字->字符 c-'0'

四、数组

五、回溯分类

  • 子集型回溯(0-1背包属于子集型)
    • 子序列本质是数组的子集,可以使用子集型回溯思考:选或不选(相邻不相关);枚举选哪个(相邻相关)
  • 组合型
  • 排列型

六、递归->记忆化搜索->动态规划

子问题和原问题是相似的,这种从原问题到子问题的过程,适合用递归解决。
递归:怎么往上「递」,怎么往下「归」

参数定义
ijk的状态分别可以表示遍历到不同的阶段,如i,j某个坐标,k是另一个子串的下标,如lc单词搜索:
枚举 i=0,1,2,…,m−1 和 j=0,1,2,…,n−1,以 (i,j) 为起点开始搜索。
同时,我们还需要知道当前匹配到了 word 的第几个字母,所以还需要一个参数 k。

递归->记忆化搜索 ->1:1改 递推。 递推初始值可以参考递归出口,递归改循环

  • 01背包:不能重复选 dfs(i-1,c)+dfs(i-1,c-nums[i])

  • 完全背包:可以重复选dfs(i-1,c)+dfs(i-,c-nums[i])

  • go 两种深拷贝写法:

    1
    2
    ans = append(ans, slices.Clone(path)) // 复制 path
    ans = append(ans, append([]int(nil), path...))

数论 & 图

  • 除了2以外其他质数都是奇数
  • 任意两个点的最短路:floyd ; 一个起点的最短路:dijstra

数学公式

向上取整:a b均为整数, 有恒等式:
$$
\left\lceil \frac{a}{b} \right\rceil
= \left\lfloor \frac{a + b - 1}{b} \right\rfloor
= \left\lfloor \frac{a - 1}{b} \right\rfloor + 1
$$

$\left\lceil \frac{a}{b} \right\rceil
= \left\lfloor \frac{a + b - 1}{b} \right\rfloor
= \left\lfloor \frac{a - 1}{b} \right\rfloor + 1$