LeetCode Hot100题解
目录
一、数组 & 字符串
1. 两数之和(简单)
2. 删除有序数组中的重复项(简单)
3. 移除元素(简单)
4. 合并两个有序数组(简单)
5. 买卖股票的最佳时机(简单)
6. 多数元素(简单)
7. 移动零(简单)
8. 三数之和(中等)
9. 无重复字符的最长子串(中等)
10. 最长回文子串(中等)
二、链表
1. 合并两个有序链表(简单)
2. 环形链表(简单)
3. 相交链表(简单)
4. 反转链表(简单)
5. 两数相加(中等)
6. 删除链表的倒数第N个结点(中等)
7. 环形链表 II(中等)
总结
三、二叉树
1. 对称二叉树(简单)
2. 二叉树的最大深度(简单)
3. 二叉树的中序遍历(中等)
4. 二叉树的层序遍历(中等)
5. 从前序与中序遍历序列构造二叉树(中等)
6. 二叉树展开为链表(中等)
总结
四、栈和队列
1. 有效的括号(简单)
2. 最小栈(中等)
3. 字符串解码(中等)
五、双指针与滑动窗口
1. 验证回文串(简单)
2. 盛最多水的容器(中等)
3. 替换后的最长重复字符(中等)
4. 字符串的排列(中等)
总结
六、动态规划
1. 爬楼梯(简单)
2. 杨辉三角(简单)
3. 最大子数组和(中等)
4. 不同路径(中等)
5. 最小路径和(中等)
6. 最长递增子序列(中等)
总结
七、回溯 & DFS
1. 括号生成(中等)
2. 全排列(中等)
3. 子集(中等)
4. 单词搜索(中等)
八、设计题
1. LRU缓存(中等)
九、排序 & 贪心
1. 合并区间(中等)
2. 颜色分类(中等)
十、位运算
1. 只出现一次的数字(简单)
总结
JavaScript实现代码
一、数组 & 字符串
1. 两数之和(Two Sum)
2. 删除有序数组中的重复项(Remove Duplicates from Sorted Array)
3. 移除元素(Remove Element)
4. 合并两个有序数组(Merge Sorted Array)
5. 买卖股票的最佳时机(Best Time to Buy and Sell Stock)
6. 多数元素(Majority Element)
7. 移动零(Move Zeroes)
8. 三数之和(3Sum)
9. 无重复字符的最长子串(Longest Substring Without Repeating Characters)
10. 最长回文子串(Longest Palindromic Substring)
二、链表
1. 合并两个有序链表(Merge Two Sorted Lists)
2. 环形链表(Linked List Cycle)
3. 相交链表(Intersection of Two Linked Lists)
4. 反转链表(Reverse Linked List)
5. 两数相加(Add Two Numbers)
6. 删除链表的倒数第N个结点(Remove Nth Node From End of List)
7. 环形链表 II(Linked List Cycle II)
三、二叉树
1. 对称二叉树(Symmetric Tree)
2. 二叉树的最大深度(Maximum Depth of Binary Tree)
3. 二叉树的中序遍历(Binary Tree Inorder Traversal)
4. 二叉树的层序遍历(Binary Tree Level Order Traversal)
5. 从前序与中序遍历序列构造二叉树(Construct Binary Tree from Preorder and Inorder Traversal)
6. 二叉树展开为链表(Flatten Binary Tree to Linked List)
四、栈 & 队列
1. 有效的括号(Valid Parentheses)
2. 最小栈(Min Stack)
3. 字符串解码(Decode String)
五、双指针 & 滑动窗口
1. 验证回文串(Valid Palindrome)
2. 盛最多水的容器(Container With Most Water)
3. 替换后的最长重复字符(Longest Repeating Character Replacement)
4. 字符串的排列(Permutation in String)
六、动态规划
1. 爬楼梯(Climbing Stairs)
2. 杨辉三角(Pascal's Triangle)
3. 最大子数组和(Maximum Subarray)
4. 不同路径(Unique Paths)
5. 最小路径和(Minimum Path Sum)
6. 最长递增子序列(Longest Increasing Subsequence)
七、回溯 & DFS
1. 括号生成(Generate Parentheses)
2. 全排列(Permutations)
3. 子集(Subsets)
4. 单词搜索(Word Search)
八、设计题
1. LRU 缓存(LRU Cache)
九、排序 & 贪心
1. 合并区间(Merge Intervals)
2. 颜色分类(Sort Colors)
十、位运算
1. 只出现一次的数字(Single Number)
本文记录LeetCode Hot100中简单和中等难度的题目,按类型分类整理,包含C++代码实现,后面有js实现的代码。
一、数组 & 字符串
1. 两数之和(简单)
题目描述
给定一个整数数组 nums
和一个整数目标值 target
,在数组中找出和为目标值 target
的两个整数,返回它们的数组下标。
示例
输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解题思路
使用哈希表存储已遍历的值及其下标,遍历时检查 target - nums[i]
是否在哈希表中。
C++代码
#include <vector>
#include <unordered_map>
using namespace std;vector<int> twoSum(vector<int>& nums, int target) {unordered_map<int, int> map;for (int i = 0; i < nums.size(); i++) {int complement = target - nums[i];if (map.count(complement)) {return {map[complement], i};}map[nums[i]] = i;}return {};
}
2. 删除有序数组中的重复项(简单)
题目描述
给定一个升序排列的数组 nums
,原地删除重复元素,使每个元素只出现一次,返回新数组的长度。
示例
输入:nums = [0,0,1,1,1,2,2,3,3,4]
输出:5
(修改后的数组为 [0,1,2,3,4]
)
解题思路
双指针法:慢指针标记唯一元素位置,快指针遍历数组。
C++代码
int removeDuplicates(vector<int>& nums) {if (nums.empty()) return 0;int slow = 0;for (int fast = 1; fast < nums.size(); fast++) {if (nums[fast] != nums[slow]) {slow++;nums[slow] = nums[fast];}}return slow + 1;
}
3. 移除元素(简单)
题目描述
给定一个数组 nums
和一个值 val
,原地移除所有数值等于 val
的元素,返回新数组的长度。
示例
输入:nums = [3,2,2,3], val = 3
输出:2
(修改后的数组为 [2,2]
)
解题思路
双指针法:慢指针标记非目标元素的位置,快指针遍历数组。
C++代码
int removeElement(vector<int>& nums, int val) {int slow = 0;for (int fast = 0; fast < nums.size(); fast++) {if (nums[fast] != val) {nums[slow++] = nums[fast];}}return slow;
}
4. 合并两个有序数组(简单)
题目描述
给定两个非递减顺序排列的整数数组 nums1
和 nums2
,将 nums2
合并到 nums1
中,使合并后的数组同样按非递减顺序排列。
示例
输入:nums1 = [1,2,3,0,0,0], m = 3
,nums2 = [2,5,6], n = 3
输出:[1,2,2,3,5,6]
解题思路
从后向前合并,避免覆盖 nums1
中的元素。
C++代码
void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {int p1 = m - 1, p2 = n - 1, p = m + n - 1;while (p2 >= 0) {if (p1 >= 0 && nums1[p1] > nums2[p2]) {nums1[p--] = nums1[p1--];} else {nums1[p--] = nums2[p2--];}}
}
5. 买卖股票的最佳时机(简单)
题目描述
给定数组 prices
,其中 prices[i]
表示股票第 i
天的价格,返回你能获取的最大利润(只能买卖一次)。
示例
输入:prices = [7,1,5,3,6,4]
输出:5
(第2天买入,第5天卖出)
解题思路
遍历数组,记录历史最低价,并计算当前最大利润。
C++代码
int maxProfit(vector<int>& prices) {int minPrice = INT_MAX, maxProfit = 0;for (int price : prices) {minPrice = min(minPrice, price);maxProfit = max(maxProfit, price - minPrice);}return maxProfit;
}
6. 多数元素(简单)
题目描述
找出数组中出现次数超过 ⌊n/2⌋
次的元素。
示例
输入:nums = [3,2,3]
输出:3
解题思路
Boyer-Moore投票算法:遇到相同元素计数+1,否则-1,计数为0时更换候选元素。
C++代码
int majorityElement(vector<int>& nums) {int candidate = nums[0], count = 0;for (int num : nums) {if (count == 0) candidate = num;count += (num == candidate) ? 1 : -1;}return candidate;
}
7. 移动零(简单)
题目描述
将数组中的所有零移动到末尾,同时保持非零元素的相对顺序。
示例
输入:nums = [0,1,0,3,12]
输出:[1,3,12,0,0]
解题思路
双指针法:将非零元素依次移到前面,最后填充零。
C++代码
void moveZeroes(vector<int>& nums) {int slow = 0;for (int fast = 0; fast < nums.size(); fast++) {if (nums[fast] != 0) {nums[slow++] = nums[fast];}}while (slow < nums.size()) {nums[slow++] = 0;}
}
8. 三数之和(中等)
题目描述
在数组 nums
中找到所有不重复的三元组 [nums[i], nums[j], nums[k]]
,使得 i != j != k
且 nums[i] + nums[j] + nums[k] = 0
。
示例
输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2], [-1,0,1]]
解题思路
排序后固定一个数,用双指针在剩余区间寻找两数之和为负数。注意去重。
C++代码
vector<vector<int>> threeSum(vector<int>& nums) {sort(nums.begin(), nums.end());vector<vector<int>> res;for (int i = 0; i < nums.size(); i++) {if (i > 0 && nums[i] == nums[i-1]) continue; // 去重int left = i + 1, right = nums.size() - 1;while (left < right) {int sum = nums[i] + nums[left] + nums[right];if (sum < 0) left++;else if (sum > 0) right--;else {res.push_back({nums[i], nums[left], nums[right]});while (left < right && nums[left] == nums[left+1]) left++; // 去重while (left < right && nums[right] == nums[right-1]) right--;left++;right--;}}}return res;
}
9. 无重复字符的最长子串(中等)
题目描述
给定一个字符串 s
,找出其中不含有重复字符的 最长子串 的长度。
示例
输入:s = "abcabcbb"
输出:3
(最长子串是 "abc"
)
解题思路
滑动窗口:用哈希表记录字符的最新位置,右指针扩展窗口,左指针跳过重复位置。
C++代码
int lengthOfLongestSubstring(string s) {unordered_map<char, int> map;int maxLen = 0, left = 0;for (int right = 0; right < s.size(); right++) {char c = s[right];if (map.count(c) && map[c] >= left) {left = map[c] + 1; // 移动左指针跳过重复}map[c] = right;maxLen = max(maxLen, right - left + 1);}return maxLen;
}
10. 最长回文子串(中等)
题目描述
给定字符串 s
,找到 s
中最长的回文子串。
示例
输入:s = "babad"
输出:"bab"
或 "aba"
解题思路
中心扩展法:遍历每个字符,尝试以该字符为中心向两边扩展,处理奇偶长度两种情况。
C++代码
string longestPalindrome(string s) {int start = 0, maxLen = 0;for (int i = 0; i < s.size(); i++) {int len1 = expand(s, i, i); // 奇长度int len2 = expand(s, i, i+1); // 偶长度int len = max(len1, len2);if (len > maxLen) {maxLen = len;start = i - (len - 1) / 2;}}return s.substr(start, maxLen);
}int expand(string s, int left, int right) {while (left >= 0 && right < s.size() && s[left] == s[right]) {left--;right++;}return right - left - 1;
}
二、链表
1. 合并两个有序链表(简单)
题目描述
将两个升序链表合并为一个新的 升序 链表并返回。
示例
输入:l1 = [1,2,4]
,l2 = [1,3,4]
输出:[1,1,2,3,4,4]
解题思路
使用虚拟头节点简化边界处理,依次比较两个链表的节点值,按升序连接。
C++代码
struct ListNode {int val;ListNode *next;ListNode(int x) : val(x), next(nullptr) {}
};ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {ListNode dummy(0); // 虚拟头节点ListNode *tail = &dummy;while (l1 && l2) {if (l1->val < l2->val) {tail->next = l1;l1 = l1->next;} else {tail->next = l2;l2 = l2->next;}tail = tail->next;}tail->next = l1 ? l1 : l2; // 连接剩余部分return dummy.next;
}
2. 环形链表(简单)
题目描述
判断链表中是否有环。
示例
输入:head = [3,2,0,-4]
(尾部节点指向索引1的节点)
输出:true
解题思路
快慢指针法:快指针每次走两步,慢指针走一步,若相遇则有环。
C++代码
bool hasCycle(ListNode *head) {if (!head) return false;ListNode *slow = head, *fast = head;while (fast && fast->next) {slow = slow->next;fast = fast->next->next;if (slow == fast) return true;}return false;
}
3. 相交链表(简单)
题目描述
找到两个单链表相交的起始节点,若不相交返回 nullptr
。
示例
输入:listA = [4,1,8,4,5]
,listB = [5,6,1,8,4,5]
(相交节点为8)
输出:相交节点值为8的节点
解题思路
双指针法:指针A遍历完链表A后转向链表B,指针B同理。两指针会在相交点相遇。
C++代码
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {ListNode *pA = headA, *pB = headB;while (pA != pB) {pA = pA ? pA->next : headB;pB = pB ? pB->next : headA;}return pA; // 若无相交,最终pA和pB均为nullptr
}
4. 反转链表(简单)
题目描述
反转单链表并返回新的头节点。
示例
输入:1->2->3->4->5
输出:5->4->3->2->1
解题思路
迭代法:维护前驱节点 prev
、当前节点 curr
,逐个反转指针方向。
C++代码
ListNode* reverseList(ListNode* head) {ListNode *prev = nullptr, *curr = head;while (curr) {ListNode *next = curr->next;curr->next = prev;prev = curr;curr = next;}return prev;
}
5. 两数相加(中等)
题目描述
给定两个非空链表,表示两个非负整数(每位数字逆序存储),返回两数之和的链表。
示例
输入:l1 = [2,4,3]
,l2 = [5,6,4]
输出:[7,0,8]
(即342 + 465 = 807)
解题思路
模拟加法过程,维护进位值 carry
,逐位相加生成新链表。
C++代码
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {ListNode dummy(0);ListNode *tail = &dummy;int carry = 0;while (l1 || l2 || carry) {int sum = carry;if (l1) {sum += l1->val;l1 = l1->next;}if (l2) {sum += l2->val;l2 = l2->next;}carry = sum / 10;tail->next = new ListNode(sum % 10);tail = tail->next;}return dummy.next;
}
6. 删除链表的倒数第N个结点(中等)
题目描述
删除链表的倒数第 n
个结点,并返回头节点。
示例
输入:head = [1,2,3,4,5]
,n = 2
输出:[1,2,3,5]
解题思路
双指针法:快指针先走 n
步,然后快慢指针同步移动,快指针到末尾时慢指针指向待删除节点的前驱。
C++代码
ListNode* removeNthFromEnd(ListNode* head, int n) {ListNode dummy(0);dummy.next = head;ListNode *fast = &dummy, *slow = &dummy;for (int i = 0; i < n; i++) fast = fast->next; // 快指针先走n步while (fast->next) {fast = fast->next;slow = slow->next;}ListNode *toDelete = slow->next;slow->next = slow->next->next;delete toDelete; // 释放内存(实际LeetCode可能不需要)return dummy.next;
}
7. 环形链表 II(中等)
题目描述
返回链表开始入环的第一个节点,若链表无环则返回 nullptr
。
示例
输入:head = [3,2,0,-4]
(尾部节点指向索引1的节点)
输出:值为2的节点
解题思路
-
快慢指针判断是否有环,并找到相遇点。
-
将快指针重置到链表头,快慢指针同步移动,再次相遇点即为环入口。
C++代码
ListNode *detectCycle(ListNode *head) {ListNode *slow = head, *fast = head;while (fast && fast->next) {slow = slow->next;fast = fast->next->next;if (slow == fast) { // 找到相遇点fast = head; // 重置快指针到头部while (slow != fast) {slow = slow->next;fast = fast->next;}return slow;}}return nullptr;
}
总结
-
双指针技巧:链表的多数问题可以通过双指针(快慢指针、前后指针)高效解决。
-
虚拟头节点:简化边界条件处理(如删除头节点或空链表)。
-
环形链表问题:快慢指针相遇后,数学推导可定位环入口。
-
注意内存管理:实际面试中可能需要手动释放删除的节点(如删除倒数第N个节点)。
三、二叉树
1. 对称二叉树(简单)
题目描述
给定二叉树的根节点 root
,检查它是否轴对称(镜像对称)。
示例
输入:root = [1,2,2,3,4,4,3]
输出:true
解题思路
递归比较左右子树是否对称:左子树的左节点与右子树的右节点、左子树的右节点与右子树的左节点均相等。
C++代码
struct TreeNode {int val;TreeNode *left;TreeNode *right;TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};bool isSymmetric(TreeNode* root) {if (!root) return true;return compare(root->left, root->right);
}bool compare(TreeNode* left, TreeNode* right) {if (!left && !right) return true;if (!left || !right) return false;return (left->val == right->val) && compare(left->left, right->right) && compare(left->right, right->left);
}
2. 二叉树的最大深度(简单)
题目描述
给定二叉树的根节点 root
,返回其最大深度(从根节点到最远叶子节点的最长路径的节点数)。
示例
输入:root = [3,9,20,null,null,15,7]
输出:3
解题思路
递归计算左右子树的最大深度,取较大者加1。
C++代码
int maxDepth(TreeNode* root) {if (!root) return 0;return 1 + max(maxDepth(root->left), maxDepth(root->right));
}
3. 二叉树的中序遍历(中等)
题目描述
给定二叉树的根节点 root
,返回它的 中序 遍历结果。
示例
输入:root = [1,null,2,3]
输出:[1,3,2]
解题思路
迭代法:使用栈模拟递归,左链入栈到底,出栈访问节点后转向右子树。
C++代码
vector<int> inorderTraversal(TreeNode* root) {vector<int> res;stack<TreeNode*> st;TreeNode* curr = root;while (curr || !st.empty()) {while (curr) { // 左链入栈到底st.push(curr);curr = curr->left;}curr = st.top();st.pop();res.push_back(curr->val);curr = curr->right; // 转向右子树}return res;
}
4. 二叉树的层序遍历(中等)
题目描述
给定二叉树的根节点 root
,返回其节点值的层序遍历结果(逐层从左到右访问)。
示例
输入:root = [3,9,20,null,null,15,7]
输出:[[3], [9,20], [15,7]]
解题思路
BFS:使用队列逐层遍历,记录每层节点数。
C++代码
vector<vector<int>> levelOrder(TreeNode* root) {vector<vector<int>> res;if (!root) return res;queue<TreeNode*> q;q.push(root);while (!q.empty()) {int levelSize = q.size();vector<int> level;for (int i = 0; i < levelSize; i++) {TreeNode* node = q.front();q.pop();level.push_back(node->val);if (node->left) q.push(node->left);if (node->right) q.push(node->right);}res.push_back(level);}return res;
}
5. 从前序与中序遍历序列构造二叉树(中等)
题目描述
给定两个整数数组 preorder
和 inorder
,构造并返回二叉树。
示例
输入:preorder = [3,9,20,15,7], inorder = [9,3,15,20,7]
输出:[3,9,20,null,null,15,7]
解题思路
-
前序数组首元素为根节点。
-
在中序数组中找到根节点位置,分割左右子树。
-
递归构建左右子树。
C++代码
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {unordered_map<int, int> map;for (int i = 0; i < inorder.size(); i++) {map[inorder[i]] = i; // 记录中序元素索引}return build(preorder, 0, preorder.size()-1, 0, map);
}TreeNode* build(vector<int>& preorder, int preStart, int preEnd, int inStart, unordered_map<int, int>& map) {if (preStart > preEnd) return nullptr;int rootVal = preorder[preStart];TreeNode* root = new TreeNode(rootVal);int rootIdx = map[rootVal]; // 中序根节点位置int leftSize = rootIdx - inStart;root->left = build(preorder, preStart+1, preStart+leftSize, inStart, map);root->right = build(preorder, preStart+leftSize+1, preEnd, rootIdx+1, map);return root;
}
6. 二叉树展开为链表(中等)
题目描述
将二叉树按前序遍历顺序展开为一个单链表(右子树连接,左子树置空)。
示例
输入:root = [1,2,5,3,4,null,6]
输出:[1,null,2,null,3,null,4,null,5,null,6]
解题思路
递归法:
-
递归展开左右子树。
-
将左子树插入到右子树的位置,并将原右子树接到左子树的最右节点。
C++代码
void flatten(TreeNode* root) {if (!root) return;flatten(root->left);flatten(root->right);TreeNode* left = root->left;TreeNode* right = root->right;root->left = nullptr;root->right = left;// 找到左子树的最右节点,连接原右子树TreeNode* curr = root;while (curr->right) {curr = curr->right;}curr->right = right;
}
总结
-
递归与分治:二叉树问题大多可通过递归分解为子树问题(如构造二叉树)。
-
遍历模板:层序遍历使用队列(BFS),中序迭代使用栈。
-
空间优化:展开链表时无需额外空间,直接修改指针。
-
边界处理:注意空节点和单子树的情况(如对称二叉树判断)。
四、栈和队列
1. 有效的括号(简单)
题目描述
给定一个只包含 '('
, ')'
, '{'
, '}'
, '['
, ']'
的字符串 s
,判断字符串是否有效(括号正确闭合)。
示例
输入:s = "()[]{}"
输出:true
解题思路
使用栈结构,遇到左括号入栈,遇到右括号检查栈顶是否匹配。
C++代码
#include <stack>
using namespace std;bool isValid(string s) {stack<char> st;for (char c : s) {if (c == '(' || c == '{' || c == '[') {st.push(c);} else {if (st.empty()) return false;char top = st.top();if ((c == ')' && top != '(') || (c == '}' && top != '{') || (c == ']' && top != '[')) {return false;}st.pop();}}return st.empty();
}
2. 最小栈(中等)
题目描述
设计一个支持 push
, pop
, top
操作,并能在常数时间内检索到最小元素的栈。
示例
输入:
push(-2)
→ push(0)
→ push(-3)
→ getMin()
→ 返回 -3
pop()
→ top()
→ 返回 0
→ getMin()
→ 返回 -2
解题思路
使用辅助栈同步记录当前最小值,或每个节点保存当前值和当前最小值。
C++代码
class MinStack {
private:struct Node {int val;int minVal;Node* next;Node(int v, int m, Node* n) : val(v), minVal(m), next(n) {}};Node* head;
public:MinStack() : head(nullptr) {}void push(int val) {if (!head) {head = new Node(val, val, nullptr);} else {head = new Node(val, min(val, head->minVal), head);}}void pop() {Node* temp = head;head = head->next;delete temp;}int top() {return head->val;}int getMin() {return head->minVal;}
};
3. 字符串解码(中等)
题目描述
给定一个编码字符串(例如 3[a2[c]]
),解码为原始字符串(accaccacc
)。
示例
输入:s = "3[a]2[bc]"
输出:"aaabcbc"
解题思路
使用栈处理嵌套结构,分别记录数字和字符串的临时结果。
C++代码
string decodeString(string s) {stack<pair<int, string>> st;int num = 0;string res = "";for (char c : s) {if (isdigit(c)) {num = num * 10 + (c - '0');} else if (c == '[') {st.push({num, res});num = 0;res = "";} else if (c == ']') {auto [repeat, prev] = st.top();st.pop();string temp = res;for (int i = 1; i < repeat; i++) {res += temp;}res = prev + res;} else {res += c;}}return res;
}
五、双指针与滑动窗口
1. 验证回文串(简单)
题目描述
给定一个字符串,验证它是否是回文串(只考虑字母和数字,忽略大小写)。
示例
输入:"A man, a plan, a canal: Panama"
输出:true
解题思路
双指针从两端向中间移动,跳过非字母数字字符并比较。
C++代码
bool isPalindrome(string s) {int left = 0, right = s.size() - 1;while (left < right) {while (left < right && !isalnum(s[left])) left++;while (left < right && !isalnum(s[right])) right--;if (tolower(s[left]) != tolower(s[right])) return false;left++;right--;}return true;
}
2. 盛最多水的容器(中等)
题目描述
给定 n
个非负整数表示容器高度,选择两个边使得容器容纳的水最多。
示例
输入:height = [1,8,6,2,5,4,8,3,7]
输出:49
(由第2和第9条边形成)
解题思路
双指针从两端向中间移动,每次移动较矮的一边以寻求更高高度。
C++代码
int maxArea(vector<int>& height) {int left = 0, right = height.size() - 1;int maxArea = 0;while (left < right) {int h = min(height[left], height[right]);maxArea = max(maxArea, h * (right - left));if (height[left] < height[right]) {left++;} else {right--;}}return maxArea;
}
3. 替换后的最长重复字符(中等)
题目描述
给定字符串 s
和整数 k
,允许替换任意字符 k
次,找到替换后最长重复字符的子串长度。
示例
输入:s = "AABABBA", k = 1
输出:4
(将中间B替换为A后得到AAAABBA
)
解题思路
滑动窗口维护窗口内最大重复字符数,窗口大小受 窗口长度 - 最大重复数 ≤ k
限制。
C++代码
int characterReplacement(string s, int k) {vector<int> count(26, 0);int maxCount = 0, maxLen = 0, left = 0;for (int right = 0; right < s.size(); right++) {maxCount = max(maxCount, ++count[s[right] - 'A']);while (right - left + 1 - maxCount > k) { // 窗口不合法时收缩左边界count[s[left] - 'A']--;left++;}maxLen = max(maxLen, right - left + 1);}return maxLen;
}
4. 字符串的排列(中等)
题目描述
判断字符串 s2
是否包含 s1
的排列作为子串。
示例
输入:s1 = "ab", s2 = "eidbaooo"
输出:true
(s2
包含"ba"
)
解题思路
滑动窗口统计字符频率,窗口长度固定为 s1
的长度。
C++代码
bool checkInclusion(string s1, string s2) {vector<int> target(26, 0), window(26, 0);for (char c : s1) target[c - 'a']++;int n = s1.size(), m = s2.size();if (n > m) return false;for (int i = 0; i < n; i++) {window[s2[i] - 'a']++;}if (window == target) return true;for (int i = n; i < m; i++) {window[s2[i - n] - 'a']--; // 移除左边界字符window[s2[i] - 'a']++; // 添加右边界字符if (window == target) return true;}return false;
}
总结
-
栈的核心应用:括号匹配、嵌套结构解析(如字符串解码)。
-
双指针方向:相向移动(盛水容器)、同向移动(滑动窗口)。
-
滑动窗口关键:维护窗口合法性条件(如替换次数限制、固定窗口长度)。
-
空间优化:频率统计替代暴力匹配(如字符串排列问题)。
六、动态规划
1. 爬楼梯(简单)
题目描述
假设你正在爬楼梯,需要 n
阶才能到达楼顶。每次可以爬 1
或 2
个台阶。求有多少种不同的方法可以爬到楼顶。
示例
输入:n = 3
输出:3
(方法:1+1+1, 1+2, 2+1)
解题思路
动态规划:状态转移方程 dp[i] = dp[i-1] + dp[i-2]
,优化空间复杂度为 O(1)
。
C++代码
int climbStairs(int n) {if (n <= 2) return n;int a = 1, b = 2, c;for (int i = 3; i <= n; i++) {c = a + b;a = b;b = c;}return b;
}
2. 杨辉三角(简单)
题目描述
给定非负整数 numRows
,生成前 numRows
行的杨辉三角。
示例
输入:numRows = 5
输出:
[[1], [1,1], [1,2,1], [1,3,3,1], [1,4,6,4,1]]
解题思路
动态规划:每一行的第 j
个元素等于上一行的 j-1
和 j
元素之和。
C++代码
vector<vector<int>> generate(int numRows) {vector<vector<int>> res;for (int i = 0; i < numRows; i++) {vector<int> row(i + 1, 1);for (int j = 1; j < i; j++) {row[j] = res[i-1][j-1] + res[i-1][j];}res.push_back(row);}return res;
}
3. 最大子数组和(中等)
题目描述
给定整数数组 nums
,找到具有最大和的连续子数组,返回其最大和。
示例
输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6
(子数组 [4,-1,2,1]
)
解题思路
Kadane算法:维护当前子数组和 curSum
和全局最大和 maxSum
。
C++代码
int maxSubArray(vector<int>& nums) {int maxSum = nums[0], curSum = nums[0];for (int i = 1; i < nums.size(); i++) {curSum = max(nums[i], curSum + nums[i]);maxSum = max(maxSum, curSum);}return maxSum;
}
4. 不同路径(中等)
题目描述
机器人从 m x n
网格的左上角移动到右下角,每次只能向右或向下移动,求总共有多少条不同的路径。
示例
输入:m = 3, n = 7
输出:28
解题思路
动态规划:状态转移方程 dp[i][j] = dp[i-1][j] + dp[i][j-1]
,空间优化为滚动数组。
C++代码
int uniquePaths(int m, int n) {vector<int> dp(n, 1);for (int i = 1; i < m; i++) {for (int j = 1; j < n; j++) {dp[j] += dp[j-1];}}return dp[n-1];
}
5. 最小路径和(中等)
题目描述
给定 m x n
网格,每个格子填非负数,找出一条从左上到右下的路径,使得路径上的数字总和最小。
示例
输入:grid = [[1,3,1],[1,5,1],[4,2,1]]
输出:7
(路径:1→3→1→1→1)
解题思路
动态规划:初始化第一行和第一列,状态转移方程为 dp[i][j] = grid[i][j] + min(dp[i-1][j], dp[i][j-1])
。
C++代码
int minPathSum(vector<vector<int>>& grid) {int m = grid.size(), n = grid[0].size();for (int i = 1; i < m; i++) grid[i][0] += grid[i-1][0];for (int j = 1; j < n; j++) grid[0][j] += grid[0][j-1];for (int i = 1; i < m; i++) {for (int j = 1; j < n; j++) {grid[i][j] += min(grid[i-1][j], grid[i][j-1]);}}return grid[m-1][n-1];
}
6. 最长递增子序列(中等)
题目描述
给定整数数组 nums
,返回最长严格递增子序列的长度。
示例
输入:nums = [10,9,2,5,3,7,101,18]
输出:4
(子序列 [2,5,7,101]
)
解题思路
动态规划:dp[i]
表示以 nums[i]
结尾的最长递增子序列长度,时间复杂度 O(n^2)
。
C++代码
int lengthOfLIS(vector<int>& nums) {int n = nums.size(), maxLen = 1;vector<int> dp(n, 1);for (int i = 1; i < n; i++) {for (int j = 0; j < i; j++) {if (nums[i] > nums[j]) {dp[i] = max(dp[i], dp[j] + 1);}}maxLen = max(maxLen, dp[i]);}return maxLen;
}
总结
-
状态定义:明确
dp[i]
或dp[i][j]
的含义(如以nums[i]
结尾的最长递增子序列长度)。 -
状态转移:找到子问题之间的关系(如爬楼梯的
dp[i] = dp[i-1] + dp[i-2]
)。 -
空间优化:用滚动数组降低维度(如不同路径问题)。
-
初始化与边界:处理第一行、第一列或空输入的情况(如最小路径和)。
七、回溯 & DFS
1. 括号生成(中等)
题目描述
给定整数 n
,生成所有包含 n
对有效括号的组合。
示例
输入:n = 3
输出:["((()))","(()())","(())()","()(())","()()()"]
解题思路
回溯法:控制左括号和右括号的数量,左括号数不能超过 n
,右括号数不能超过左括号数。
C++代码
vector<string> generateParenthesis(int n) {vector<string> res;backtrack(res, "", 0, 0, n);return res;
}void backtrack(vector<string>& res, string cur, int left, int right, int n) {if (cur.size() == 2 * n) {res.push_back(cur);return;}if (left < n) backtrack(res, cur + "(", left + 1, right, n);if (right < left) backtrack(res, cur + ")", left, right + 1, n);
}
2. 全排列(中等)
题目描述
给定不含重复数字的数组 nums
,返回其所有可能的全排列。
示例
输入:nums = [1,2,3]
输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
解题思路
回溯法:通过交换元素实现排列,递归结束后恢复原数组。
C++代码
vector<vector<int>> permute(vector<int>& nums) {vector<vector<int>> res;backtrack(nums, 0, res);return res;
}void backtrack(vector<int>& nums, int start, vector<vector<int>>& res) {if (start == nums.size()) {res.push_back(nums);return;}for (int i = start; i < nums.size(); i++) {swap(nums[start], nums[i]);backtrack(nums, start + 1, res);swap(nums[start], nums[i]); // 恢复数组}
}
3. 子集(中等)
题目描述
给定整数数组 nums
(元素互不相同),返回所有可能的子集(幂集)。
示例
输入:nums = [1,2,3]
输出:[[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]
解题思路
迭代法:逐步将新元素添加到已有的子集中生成新子集。
C++代码
vector<vector<int>> subsets(vector<int>& nums) {vector<vector<int>> res = {{}};for (int num : nums) {int size = res.size();for (int i = 0; i < size; i++) {vector<int> subset = res[i];subset.push_back(num);res.push_back(subset);}}return res;
}
4. 单词搜索(中等)
题目描述
给定 m x n
二维字符网格 board
和字符串 word
,判断 word
是否存在于网格中。
示例
输入:board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "ABCCED"
输出:true
解题思路
DFS 回溯:遍历每个起点,递归搜索四个方向,标记已访问的位置。
C++代码
bool exist(vector<vector<char>>& board, string word) {for (int i = 0; i < board.size(); i++) {for (int j = 0; j < board[0].size(); j++) {if (dfs(board, word, i, j, 0)) return true;}}return false;
}bool dfs(vector<vector<char>>& board, string& word, int i, int j, int idx) {if (idx == word.size()) return true;if (i < 0 || i >= board.size() || j < 0 || j >= board[0].size() || board[i][j] != word[idx]) return false;char temp = board[i][j];board[i][j] = '#'; // 标记已访问bool found = dfs(board, word, i+1, j, idx+1) ||dfs(board, word, i-1, j, idx+1) ||dfs(board, word, i, j+1, idx+1) ||dfs(board, word, i, j-1, idx+1);board[i][j] = temp; // 恢复return found;
}
八、设计题
1. LRU缓存(中等)
题目描述
设计并实现一个 LRU(最近最少使用)缓存机制,支持 get
和 put
操作。
示例
输入:
capacity = 2
put(1,1); put(2,2); get(1); put(3,3);
输出:get(1)=1
→ put(3)
后缓存为 {1=1,3=3}
解题思路
哈希表 + 双向链表:哈希表快速定位节点,双向链表维护访问顺序。
C++代码
class LRUCache {
private:struct Node {int key, val;Node *prev, *next;Node(int k, int v) : key(k), val(v), prev(nullptr), next(nullptr) {}};Node *head, *tail;unordered_map<int, Node*> map;int cap;void remove(Node* node) {node->prev->next = node->next;node->next->prev = node->prev;}void addToHead(Node* node) {node->next = head->next;node->prev = head;head->next->prev = node;head->next = node;}public:LRUCache(int capacity) : cap(capacity) {head = new Node(-1, -1);tail = new Node(-1, -1);head->next = tail;tail->prev = head;}int get(int key) {if (!map.count(key)) return -1;Node* node = map[key];remove(node);addToHead(node);return node->val;}void put(int key, int value) {if (map.count(key)) {Node* node = map[key];node->val = value;remove(node);addToHead(node);} else {if (map.size() == cap) {Node* last = tail->prev;remove(last);map.erase(last->key);delete last;}Node* newNode = new Node(key, value);map[key] = newNode;addToHead(newNode);}}
};
九、排序 & 贪心
1. 合并区间(中等)
题目描述
给定多个区间,合并所有重叠的区间。
示例
输入:intervals = [[1,3],[2,6],[8,10],[15,18]]
输出:[[1,6],[8,10],[15,18]]
解题思路
排序后贪心:按区间起点排序,遍历合并重叠区间。
C++代码
vector<vector<int>> merge(vector<vector<int>>& intervals) {if (intervals.empty()) return {};sort(intervals.begin(), intervals.end());vector<vector<int>> res = {intervals[0]};for (auto& interval : intervals) {if (interval[0] <= res.back()[1]) {res.back()[1] = max(res.back()[1], interval[1]);} else {res.push_back(interval);}}return res;
}
2. 颜色分类(中等)
题目描述
给定包含 0, 1, 2
的数组,原地排序使相同颜色相邻(荷兰国旗问题)。
示例
输入:nums = [2,0,2,1,1,0]
输出:[0,0,1,1,2,2]
解题思路
三指针分区:left
标记 0 的右边界,right
标记 2 的左边界,curr
遍历数组。
C++代码
void sortColors(vector<int>& nums) {int left = 0, right = nums.size() - 1, curr = 0;while (curr <= right) {if (nums[curr] == 0) {swap(nums[curr++], nums[left++]);} else if (nums[curr] == 2) {swap(nums[curr], nums[right--]);} else {curr++;}}
}
十、位运算
1. 只出现一次的数字(简单)
题目描述
给定非空数组,其中某个元素只出现一次,其余均出现两次,找出该元素。
示例
输入:nums = [4,1,2,1,2]
输出:4
解题思路
异或运算:a ^ a = 0
,a ^ 0 = a
,所有元素异或后结果为唯一数。
C++代码
int singleNumber(vector<int>& nums) {int res = 0;for (int num : nums) res ^= num;return res;
}
总结
-
回溯核心:通过递归探索所有可能路径,必要时剪枝(如括号生成中的合法性判断)。
-
设计题重点:数据结构的选择(如 LRU 缓存的双向链表 + 哈希表)。
-
排序预处理:合并区间问题需先排序以简化贪心逻辑。
-
位运算技巧:异或操作消除重复项,三指针原地分区(颜色分类)。
JavaScript实现代码
一、数组 & 字符串
1. 两数之和(Two Sum)
function twoSum(nums, target) {const map = new Map();for (let i = 0; i < nums.length; i++) {const complement = target - nums[i];if (map.has(complement)) {return [map.get(complement), i];}map.set(nums[i], i);}return [];
}
2. 删除有序数组中的重复项(Remove Duplicates from Sorted Array)
function removeDuplicates(nums) {if (nums.length === 0) return 0;let slow = 0;for (let fast = 1; fast < nums.length; fast++) {if (nums[fast] !== nums[slow]) {slow++;nums[slow] = nums[fast];}}return slow + 1;
}
3. 移除元素(Remove Element)
function removeElement(nums, val) {let slow = 0;for (let fast = 0; fast < nums.length; fast++) {if (nums[fast] !== val) {nums[slow++] = nums[fast];}}return slow;
}
4. 合并两个有序数组(Merge Sorted Array)
function merge(nums1, m, nums2, n) {let p1 = m - 1, p2 = n - 1, p = m + n - 1;while (p2 >= 0) {if (p1 >= 0 && nums1[p1] > nums2[p2]) {nums1[p--] = nums1[p1--];} else {nums1[p--] = nums2[p2--];}}
}
5. 买卖股票的最佳时机(Best Time to Buy and Sell Stock)
function maxProfit(prices) {let minPrice = Infinity, maxProfit = 0;for (const price of prices) {minPrice = Math.min(minPrice, price);maxProfit = Math.max(maxProfit, price - minPrice);}return maxProfit;
}
6. 多数元素(Majority Element)
function majorityElement(nums) {let count = 0, candidate = null;for (const num of nums) {if (count === 0) candidate = num;count += (num === candidate) ? 1 : -1;}return candidate;
}
7. 移动零(Move Zeroes)
function moveZeroes(nums) {let slow = 0;for (let fast = 0; fast < nums.length; fast++) {if (nums[fast] !== 0) {nums[slow++] = nums[fast];}}while (slow < nums.length) {nums[slow++] = 0;}
}
8. 三数之和(3Sum)
function threeSum(nums) {nums.sort((a, b) => a - b);const res = [];for (let i = 0; i < nums.length - 2; i++) {if (i > 0 && nums[i] === nums[i - 1]) continue;let left = i + 1, right = nums.length - 1;while (left < right) {const sum = nums[i] + nums[left] + nums[right];if (sum < 0) left++;else if (sum > 0) right--;else {res.push([nums[i], nums[left], nums[right]]);while (left < right && nums[left] === nums[left + 1]) left++;while (left < right && nums[right] === nums[right - 1]) right--;left++;right--;}}}return res;
}
9. 无重复字符的最长子串(Longest Substring Without Repeating Characters)
function lengthOfLongestSubstring(s) {const map = new Map();let max = 0, left = 0;for (let right = 0; right < s.length; right++) {const c = s[right];if (map.has(c) && map.get(c) >= left) {left = map.get(c) + 1;}map.set(c, right);max = Math.max(max, right - left + 1);}return max;
}
10. 最长回文子串(Longest Palindromic Substring)
function longestPalindrome(s) {let max = '';for (let i = 0; i < s.length; i++) {const len1 = expand(s, i, i);const len2 = expand(s, i, i + 1);const longer = len1.length > len2.length ? len1 : len2;if (longer.length > max.length) max = longer;}return max;
}function expand(s, left, right) {while (left >= 0 && right < s.length && s[left] === s[right]) {left--;right++;}return s.slice(left + 1, right);
}
二、链表
1. 合并两个有序链表(Merge Two Sorted Lists)
function mergeTwoLists(l1, l2) {const dummy = new ListNode(-1);let current = dummy;while (l1 && l2) {if (l1.val < l2.val) {current.next = l1;l1 = l1.next;} else {current.next = l2;l2 = l2.next;}current = current.next;}current.next = l1 || l2;return dummy.next;
}class ListNode {constructor(val, next = null) {this.val = val;this.next = next;}
}
2. 环形链表(Linked List Cycle)
function hasCycle(head) {let slow = head, fast = head;while (fast && fast.next) {slow = slow.next;fast = fast.next.next;if (slow === fast) return true;}return false;
}
3. 相交链表(Intersection of Two Linked Lists)
function getIntersectionNode(headA, headB) {let pA = headA, pB = headB;while (pA !== pB) {pA = pA ? pA.next : headB;pB = pB ? pB.next : headA;}return pA;
}
4. 反转链表(Reverse Linked List)
function reverseList(head) {let prev = null, curr = head;while (curr) {const next = curr.next;curr.next = prev;prev = curr;curr = next;}return prev;
}
5. 两数相加(Add Two Numbers)
function addTwoNumbers(l1, l2) {const dummy = new ListNode(0);let curr = dummy, carry = 0;while (l1 || l2 || carry) {const sum = (l1?.val || 0) + (l2?.val || 0) + carry;carry = Math.floor(sum / 10);curr.next = new ListNode(sum % 10);curr = curr.next;l1 = l1?.next;l2 = l2?.next;}return dummy.next;
}
6. 删除链表的倒数第N个结点(Remove Nth Node From End of List)
function removeNthFromEnd(head, n) {const dummy = new ListNode(0, head);let fast = dummy, slow = dummy;for (let i = 0; i < n; i++) fast = fast.next;while (fast.next) {fast = fast.next;slow = slow.next;}slow.next = slow.next.next;return dummy.next;
}
7. 环形链表 II(Linked List Cycle II)
function detectCycle(head) {let slow = head, fast = head;while (fast && fast.next) {slow = slow.next;fast = fast.next.next;if (slow === fast) {fast = head;while (slow !== fast) {slow = slow.next;fast = fast.next;}return slow;}}return null;
}
三、二叉树
1. 对称二叉树(Symmetric Tree)
function isSymmetric(root) {if (!root) return true;return compare(root.left, root.right);
}function compare(left, right) {if (!left && !right) return true;if (!left || !right || left.val !== right.val) return false;return compare(left.left, right.right) && compare(left.right, right.left);
}
2. 二叉树的最大深度(Maximum Depth of Binary Tree)
function maxDepth(root) {if (!root) return 0;return 1 + Math.max(maxDepth(root.left), maxDepth(root.right));
}
3. 二叉树的中序遍历(Binary Tree Inorder Traversal)
function inorderTraversal(root) {const res = [];const stack = [];let curr = root;while (curr || stack.length) {while (curr) {stack.push(curr);curr = curr.left;}curr = stack.pop();res.push(curr.val);curr = curr.right;}return res;
}
4. 二叉树的层序遍历(Binary Tree Level Order Traversal)
function levelOrder(root) {const res = [];if (!root) return res;const queue = [root];while (queue.length) {const levelSize = queue.length;const level = [];for (let i = 0; i < levelSize; i++) {const node = queue.shift();level.push(node.val);if (node.left) queue.push(node.left);if (node.right) queue.push(node.right);}res.push(level);}return res;
}
5. 从前序与中序遍历序列构造二叉树(Construct Binary Tree from Preorder and Inorder Traversal)
function buildTree(preorder, inorder) {const map = new Map();for (let i = 0; i < inorder.length; i++) map.set(inorder[i], i);return build(0, preorder.length - 1, 0, inorder.length - 1);function build(preStart, preEnd, inStart, inEnd) {if (preStart > preEnd) return null;const rootVal = preorder[preStart];const root = new TreeNode(rootVal);const rootIdx = map.get(rootVal);const leftSize = rootIdx - inStart;root.left = build(preStart + 1, preStart + leftSize, inStart, rootIdx - 1);root.right = build(preStart + leftSize + 1, preEnd, rootIdx + 1, inEnd);return root;}
}class TreeNode {constructor(val, left = null, right = null) {this.val = val;this.left = left;this.right = right;}
}
6. 二叉树展开为链表(Flatten Binary Tree to Linked List)
function flatten(root) {let curr = root;while (curr) {if (curr.left) {const predecessor = findRightmost(curr.left);predecessor.right = curr.right;curr.right = curr.left;curr.left = null;}curr = curr.right;}
}function findRightmost(node) {while (node.right) node = node.right;return node;
}
四、栈 & 队列
1. 有效的括号(Valid Parentheses)
function isValid(s) {const stack = [];const map = { '(': ')', '{': '}', '[': ']' };for (const c of s) {if (c in map) {stack.push(c);} else {if (!stack.length || map[stack.pop()] !== c) return false;}}return !stack.length;
}
2. 最小栈(Min Stack)
class MinStack {constructor() {this.stack = [];this.minStack = [];}push(val) {this.stack.push(val);if (this.minStack.length === 0 || val <= this.minStack[this.minStack.length - 1]) {this.minStack.push(val);}}pop() {const val = this.stack.pop();if (val === this.minStack[this.minStack.length - 1]) {this.minStack.pop();}}top() {return this.stack[this.stack.length - 1];}getMin() {return this.minStack[this.minStack.length - 1];}
}
3. 字符串解码(Decode String)
function decodeString(s) {const stack = [];let num = 0, str = '';for (const c of s) {if (/\d/.test(c)) {num = num * 10 + parseInt(c);} else if (c === '[') {stack.push(str);stack.push(num);str = '';num = 0;} else if (c === ']') {const repeat = stack.pop();const prevStr = stack.pop();str = prevStr + str.repeat(repeat);} else {str += c;}}return str;
}
五、双指针 & 滑动窗口
1. 验证回文串(Valid Palindrome)
function isPalindrome(s) {s = s.replace(/[^a-z0-9]/gi, '').toLowerCase();let left = 0, right = s.length - 1;while (left < right) {if (s[left++] !== s[right--]) return false;}return true;
}
2. 盛最多水的容器(Container With Most Water)
function maxArea(height) {let left = 0, right = height.length - 1, max = 0;while (left < right) {const area = Math.min(height[left], height[right]) * (right - left);max = Math.max(max, area);height[left] < height[right] ? left++ : right--;}return max;
}
3. 替换后的最长重复字符(Longest Repeating Character Replacement)
function characterReplacement(s, k) {const count = new Array(26).fill(0);let left = 0, maxCount = 0, maxLen = 0;for (let right = 0; right < s.length; right++) {const idx = s.charCodeAt(right) - 'A'.charCodeAt(0);maxCount = Math.max(maxCount, ++count[idx]);while (right - left + 1 - maxCount > k) {count[s.charCodeAt(left) - 'A'.charCodeAt(0)]--;left++;}maxLen = Math.max(maxLen, right - left + 1);}return maxLen;
}
4. 字符串的排列(Permutation in String)
function checkInclusion(s1, s2) {const target = new Array(26).fill(0);const window = new Array(26).fill(0);for (const c of s1) target[c.charCodeAt() - 97]++;let left = 0;for (let right = 0; right < s2.length; right++) {const c = s2[right].charCodeAt() - 97;window[c]++;while (window[c] > target[c]) {window[s2[left++].charCodeAt() - 97]--;}if (right - left + 1 === s1.length) return true;}return false;
}
六、动态规划
1. 爬楼梯(Climbing Stairs)
function climbStairs(n) {if (n <= 2) return n;let a = 1, b = 2;for (let i = 3; i <= n; i++) [a, b] = [b, a + b];return b;
}
2. 杨辉三角(Pascal's Triangle)
function generate(numRows) {const res = [];for (let i = 0; i < numRows; i++) {const row = new Array(i + 1).fill(1);for (let j = 1; j < i; j++) {row[j] = res[i - 1][j - 1] + res[i - 1][j];}res.push(row);}return res;
}
3. 最大子数组和(Maximum Subarray)
function maxSubArray(nums) {let max = nums[0], curr = nums[0];for (let i = 1; i < nums.length; i++) {curr = Math.max(nums[i], curr + nums[i]);max = Math.max(max, curr);}return max;
}
4. 不同路径(Unique Paths)
function uniquePaths(m, n) {const dp = new Array(n).fill(1);for (let i = 1; i < m; i++) {for (let j = 1; j < n; j++) {dp[j] += dp[j - 1];}}return dp[n - 1];
}
5. 最小路径和(Minimum Path Sum)
function minPathSum(grid) {const m = grid.length, n = grid[0].length;for (let i = 1; i < m; i++) grid[i][0] += grid[i - 1][0];for (let j = 1; j < n; j++) grid[0][j] += grid[0][j - 1];for (let i = 1; i < m; i++) {for (let j = 1; j < n; j++) {grid[i][j] += Math.min(grid[i - 1][j], grid[i][j - 1]);}}return grid[m - 1][n - 1];
}
6. 最长递增子序列(Longest Increasing Subsequence)
function lengthOfLIS(nums) {const dp = new Array(nums.length).fill(1);let max = 1;for (let i = 1; i < nums.length; i++) {for (let j = 0; j < i; j++) {if (nums[i] > nums[j]) dp[i] = Math.max(dp[i], dp[j] + 1);}max = Math.max(max, dp[i]);}return max;
}
七、回溯 & DFS
1. 括号生成(Generate Parentheses)
function generateParenthesis(n) {const res = [];backtrack("", 0, 0);return res;function backtrack(s, left, right) {if (s.length === 2 * n) {res.push(s);return;}if (left < n) backtrack(s + "(", left + 1, right);if (right < left) backtrack(s + ")", left, right + 1);}
}
2. 全排列(Permutations)
function permute(nums) {const res = [];backtrack(0);return res;function backtrack(start) {if (start === nums.length) {res.push([...nums]);return;}for (let i = start; i < nums.length; i++) {[nums[start], nums[i]] = [nums[i], nums[start]];backtrack(start + 1);[nums[start], nums[i]] = [nums[i], nums[start]];}}
}
3. 子集(Subsets)
function subsets(nums) {const res = [[]];for (const num of nums) {const size = res.length;for (let i = 0; i < size; i++) {res.push([...res[i], num]);}}return res;
}
4. 单词搜索(Word Search)
function exist(board, word) {const m = board.length, n = board[0].length;for (let i = 0; i < m; i++) {for (let j = 0; j < n; j++) {if (dfs(i, j, 0)) return true;}}return false;function dfs(i, j, idx) {if (idx === word.length) return true;if (i < 0 || i >= m || j < 0 || j >= n || board[i][j] !== word[idx]) return false;const temp = board[i][j];board[i][j] = "#";const found = dfs(i + 1, j, idx + 1) || dfs(i - 1, j, idx + 1) ||dfs(i, j + 1, idx + 1) || dfs(i, j - 1, idx + 1);board[i][j] = temp;return found;}
}
八、设计题
1. LRU 缓存(LRU Cache)
class LRUCache {constructor(capacity) {this.capacity = capacity;this.cache = new Map();}get(key) {if (!this.cache.has(key)) return -1;const value = this.cache.get(key);this.cache.delete(key);this.cache.set(key, value);return value;}put(key, value) {if (this.cache.has(key)) this.cache.delete(key);this.cache.set(key, value);if (this.cache.size > this.capacity) {this.cache.delete(this.cache.keys().next().value);}}
}
九、排序 & 贪心
1. 合并区间(Merge Intervals)
function merge(intervals) {intervals.sort((a, b) => a[0] - b[0]);const res = [intervals[0]];for (let i = 1; i < intervals.length; i++) {const last = res[res.length - 1];if (intervals[i][0] <= last[1]) {last[1] = Math.max(last[1], intervals[i][1]);} else {res.push(intervals[i]);}}return res;
}
2. 颜色分类(Sort Colors)
function sortColors(nums) {let left = 0, right = nums.length - 1, curr = 0;while (curr <= right) {if (nums[curr] === 0) {[nums[curr], nums[left]] = [nums[left], nums[curr]];left++;curr++;} else if (nums[curr] === 2) {[nums[curr], nums[right]] = [nums[right], nums[curr]];right--;} else {curr++;}}
}
十、位运算
1. 只出现一次的数字(Single Number)
function singleNumber(nums) {return nums.reduce((acc, num) => acc ^ num, 0);
}