链表
java
/反转链表
迭代
ListNode reverseList(ListNode head) {
ListNode prev = null, cur = head;
while (cur != null) {
ListNode next = cur.next; // 1. 先存下一个,防断链
cur.next = prev; // 2. 反转当前指针
prev = cur; // 3. prev 前进
cur = next; // 4. cur 前进
}
return prev; // prev 是新头
}
递归
ListNode reverseList(ListNode head) {
if (head == null || head.next == null) return head;
ListNode newHead = reverseList(head.next); // 先反转后面
head.next.next = head; // 让后一个节点指回自己
head.next = null; // 断开原方向,防成环
return newHead;
}
/快慢指针
ListNode slow = head, fast = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
}
return slow;
}
boolean hasCycle(ListNode head) {
ListNode slow = head, fast = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
if (slow == fast) return true; // 相遇
}
return false;
}
虚拟dummy
ListNode dummy = new ListNode(0);
dummy.next = head;
ListNode cur = dummy;
// ... 操作 ...
return dummy.next; // 真正的头可能被改,返回 dummy.next
二叉树DFS
java
/二叉树递归骨架
// 104 最大深度:分解型,f(node) = max(f(left), f(right)) + 1
int maxDepth(TreeNode root) {
if (root == null) return 0;
return Math.max(maxDepth(root.left), maxDepth(root.right)) + 1;
}
// 226 翻转二叉树:遍历型,交换左右子树后递归
TreeNode invertTree(TreeNode root) {
if (root == null) return null;
TreeNode left = invertTree(root.left); // 先递归翻转
root.left = invertTree(root.right);
root.right = left;
return root;
}
/直径与 LCA
// 543 直径:后序,每个节点算「左深+右深」更新全局最大,返回自身深度
int ans = 0;
int diameter(TreeNode root) {
if (root == null) return 0;
int l = diameter(root.left), r = diameter(root.right);
ans = Math.max(ans, l + r); // 经过该节点的最长路径
return Math.max(l, r) + 1; // 向上返回深度
}
// 236 最近公共祖先:后序,左右各找到一个目标则当前节点即 LCA
TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if (root == null || root == p || root == q) return root;
TreeNode left = lowestCommonAncestor(root.left, p, q);
TreeNode right = lowestCommonAncestor(root.right, p, q);
if (left != null && right != null) return root; // p、q 分居两侧
return left != null ? left : right; // 都在同一侧
}
回溯
java
/回溯通用框架
List<List<Integer>> res = new ArrayList<>();
void backtrack(int[] nums, List<Integer> path, boolean[] used) {
if (path.size() == nums.length) { // 结束条件:选满了
res.add(new ArrayList<>(path)); // 注意:必须 new 一份拷贝
return;
}
for (int i = 0; i < nums.length; i++) { // 遍历选择列表
if (used[i]) continue; // 跳过已选
path.add(nums[i]); used[i] = true; // 【做选择】
backtrack(nums, path, used); // 递归下一层
path.remove(path.size() - 1); used[i] = false; // 【撤销选择】
}
}
/排列 / 组合/子集
// 组合/子集:用 start 控制起点,避免重复选(顺序无关)
void backtrack(int[] nums, int start, List<Integer> path) {
res.add(new ArrayList<>(path)); // 子集:每个节点都是答案
for (int i = start; i < nums.length; i++) {
path.add(nums[i]);
backtrack(nums, i + 1, path); // 传 i+1,不回头
path.remove(path.size() - 1);
}
}
/含重复元素去重
Arrays.sort(nums); // 先排序,让相同元素相邻
void backtrack(int[] nums, int start, boolean[] used, List<Integer> path) {
// ...收集答案...
for (int i = start; i < nums.length; i++) {
// 同一层里,跳过重复元素(前一个相同值没被用,说明同层已处理过)
if (i > start && nums[i] == nums[i-1]) continue;
if (used[i]) continue;
// 做选择 / 递归 / 撤销
}
}