刷题笔记

106 阅读6分钟

一、数学问题

50. Pow(x, n)

  • 思路:利用快速幂算法,将指数分解为二进制位,通过位运算逐位处理。若指数为负数,先转化为正数计算,结果取倒数。

  • 关键点:位运算优化(n & 1判断奇偶,n >>= 1右移),处理int负数溢出(用long存储指数)。

66. 加一

  • 思路:从数组末位开始处理进位,若末位非9则直接加一;若全为9,创建长度+1的新数组,首位为1。

  • 关键点:循环处理进位,处理全9的边界情况。

69. x的平方根

  • 思路:二分查找法,在[0, x]范围内查找最大整数m,使得m² ≤ x,处理整数溢出(用long计算)。

  • 关键点:二分模板(left <= right),返回right作为结果。

二、字符串处理

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

  • 思路:滑动窗口+哈希集合,右指针扩展窗口,左指针收缩至无重复字符,记录最大窗口长度。

  • 关键点HashSet存储窗口内字符,处理重复时左指针移动并移除重复字符。

5. 最长回文子串

  • 思路:中心扩展法,以每个字符为中心向两侧扩展,比较奇数和偶数长度的回文串,记录最长子串。

  • 关键点:双中心扩展(单字符中心、双字符中心),更新最长子串的起始和结束位置。

8. 字符串转换整数 (atoi)

  • 思路:正则匹配+状态机,处理空格、符号、数字,处理越界(用long存储结果)。

  • 关键点:正则表达式过滤非法字符,越界时返回边界值(Integer.MAX_VALUE/MIN_VALUE)。

三、 哈希表 应用

1. 两数之和

  • 思路:哈希表存储已遍历元素的值和下标,遍历数组时查找target - nums[i]是否存在,存在则返回下标。

  • 关键点:哈希表快速查找,处理重复元素时保证下标唯一。

36. 有效的数独

  • 思路:用三个哈希表分别记录每行、每列、每个九宫格的数字出现次数,遍历棋盘验证唯一性。

  • 关键点:九宫格索引计算((i/3)*3 + j/3),避免重复判断。

49. 字母异位词分组

  • 思路:将字符串排序后作为键,原字符串作为值存入哈希表,同一键下的字符串为字母异位词。

  • 关键点:排序后的字符串作为唯一键,利用computeIfAbsent简化代码。

四、 双指针 技巧

27. 移动零

  • 思路:双指针法,快指针遍历数组,慢指针记录非零元素位置,最后将慢指针后的元素置零。

  • 关键点:快指针跳过零元素,慢指针复制非零元素。

11. 盛最多水的容器

  • 思路:双指针从两端移动,每次移动较短板,计算当前面积并更新最大值。

  • 关键点:贪心策略(移动短边可能找到更大面积),数学证明(短边限制面积上限)。

15. 三数之和

  • 思路:排序后固定一数,双指针找另外两数,跳过重复元素避免重复解。

  • 关键点:排序去重,双指针移动逻辑(根据和的大小调整指针)。

五、动态规划

70. 爬楼梯

  • 思路:动态规划,状态转移方程dp[i] = dp[i-1] + dp[i-2],初始化dp[1]=1, dp[2]=2,迭代计算。

  • 关键点:空间优化(仅用两个变量存储前两项),避免数组空间浪费。

198. 打家劫舍

  • 思路:动态规划,状态转移方程dp[i] = max(dp[i-1], dp[i-2] + nums[i]),表示不抢或抢当前房屋的最大值。

  • 关键点:滚动数组优化,避免存储整个dp数组。

300. 最长递增子序列

  • 思路:动态规划,dp[i]表示以nums[i]结尾的最长递增子序列长度,遍历前序元素更新dp[i]

  • 关键点:时间复杂度O(n²),可优化为O(n log n)(贪心+二分)。

六、二叉树算法

94. 二叉树的 中序遍历

  • 思路:递归实现中序遍历(左-根-右),迭代法用栈模拟递归过程。

  • 关键点:递归终止条件(节点为空),迭代时栈存储待访问节点。

104. 二叉树的最大深度

  • 思路:后序遍历(DFS),递归计算左右子树深度,当前节点深度为最大值+1。

  • 关键点:递归返回值为子树深度,空节点深度为0。

114. 二叉树展开为 链表

  • 思路:前序遍历展开,用指针记录前驱节点,将左子树插入到右子树位置。

  • 关键点:递归展开左子树和右子树,处理指针连接顺序。

七、回溯算法

46. 全排列

  • 思路:回溯法,用标记数组记录已使用元素,递归生成排列,回溯时撤销选择。

  • 关键点:递归参数(路径、标记数组),终止条件(路径长度等于数组长度)。

78. 子集

  • 思路:回溯法,从每个位置开始选择包含或不包含当前元素,避免重复组合(通过起始索引控制)。

  • 关键点:收集所有路径(包括空集),起始索引避免重复选择。

90. 子集 II

  • 思路:回溯法,排序数组后跳过重复元素,避免生成重复子集。

  • 关键点:排序去重,i > start时判断重复(nums[i] == nums[i-1])。

八、贪心算法

121. 买卖股票的最佳时机

  • 思路:贪心遍历,记录当前最小值,计算当前价格与最小值的差值,更新最大利润。

  • 关键点:一次遍历,时间复杂度O(n)

455. 分发饼干

  • 思路:贪心排序,小饼干优先满足需求小的孩子,双指针匹配。

  • 关键点:排序后双指针移动(饼干和孩子需求均升序)。

55. 跳跃游戏

  • 思路:贪心维护当前最大覆盖范围,遍历数组判断是否可到达终点。

  • 关键点:更新最大覆盖范围,若当前位置超过覆盖范围则返回false。

九、图论与BFS/DFS

200. 岛屿数量

  • 思路:DFS/BFS,遍历每个单元格,遇到陆地则递归/迭代标记相邻陆地为已访问,统计岛屿数。

  • 关键点:标记已访问单元格(改为'0'或使用visited数组),四个方向扩展(上下左右)。

127. 单词接龙

  • 思路:BFS,构建单词图,每次变换一个字符,记录层次(最短变换次数)。

  • 关键点:双向BFS优化,避免单向BFS的高时间复杂度。

十、其他算法(二分、栈、队列等)

33. 搜索旋转排序数组

  • 思路:二分查找,先确定旋转点,再根据目标值与最后一个元素的大小关系,在相应有序区间查找。

  • 关键点:判断当前中点属于左半区还是右半区,调整二分区间。

155. 最小栈

  • 思路:栈+辅助栈,辅助栈记录当前栈中的最小值,保证push、pop、top、getMin均为O(1)时间复杂度。

  • 关键点:辅助栈与数据栈同步操作,存储历史最小值。