1. LeetCode 1-25题算法精解入门指南
作为程序员面试的"金标准",LeetCode前25道简单题是每个开发者算法之旅的起点。这些题目看似基础,却涵盖了数组操作、字符串处理、哈希表应用等编程核心技能。我在硅谷科技公司担任面试官五年间,发现80%的候选人都会在这些"简单题"上暴露出基础不扎实的问题——不是算法思路错误,就是边界条件处理不当。
这套题目的价值在于:它们像乐高积木一样,构成了更复杂算法的基本单元。比如第1题"两数之和"教会我们如何用空间换时间,第20题"有效的括号"是栈结构的经典应用,而第21题"合并两个有序链表"则是分治思想的启蒙。掌握这些题目,相当于获得了破解中等难度题的万能钥匙。
提示:不要被"简单"标签迷惑,建议每个题目至少用两种方法实现,并比较时间/空间复杂度差异
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 核心题目分类与解题框架
2.1 数组类问题(第1、26、27题)
**两数之和(第1题)**的暴力解法是O(n²)的双层循环,但用哈希表可以将时间复杂度降到O(n)。这里有个易错点:要先检查target-nums[i]是否在哈希表中,再存入当前元素,否则会错误匹配自身。Python实现示例:
python复制def twoSum(nums, target):
hashmap = {}
for i, num in enumerate(nums):
complement = target - num
if complement in hashmap:
return [hashmap[complement], i]
hashmap[num] = i
**删除有序数组重复项(第26题)**采用快慢指针法,slow指针标记唯一元素位置,fast指针探索新元素。关键判断条件是nums[fast] != nums[slow],此时应先将slow前移再赋值:
python复制def removeDuplicates(nums):
if not nums: return 0
slow = 0
for fast in range(1, len(nums)):
if nums[fast] != nums[slow]:
slow += 1
nums[slow] = nums[fast]
return slow + 1
2.2 字符串操作(第14、20题)
**最长公共前缀(第14题)**的垂直扫描法比水平扫描更高效。逐个字符比较所有字符串,直到出现不匹配或某个字符串结束。注意处理空输入的情况:
python复制def longestCommonPrefix(strs):
if not strs: return ""
for i in range(len(strs[0])):
char = strs[0][i]
for s in strs[1:]:
if i == len(s) or s[i] != char:
return strs[0][:i]
return strs[0]
**有效括号(第20题)**需要使用栈结构,遇到左括号入栈,右括号时检查栈顶是否匹配。特别注意最终要检查栈是否为空,否则会漏判"((()"这种情况:
python复制def isValid(s):
stack = []
mapping = {")": "(", "}": "{", "]": "["}
for char in s:
if char in mapping:
top = stack.pop() if stack else '#'
if mapping[char] != top:
return False
else:
stack.append(char)
return not stack
3. 链表基础操作精要
3.1 合并有序链表(第21题)
这道题展示了递归和迭代两种解法的典型范式。递归解法简洁但空间复杂度O(n),迭代解法O(1)空间更优:
python复制# 迭代解法
def mergeTwoLists(l1, l2):
dummy = ListNode(-1)
prev = dummy
while l1 and l2:
if l1.val <= l2.val:
prev.next = l1
l1 = l1.next
else:
prev.next = l2
l2 = l2.next
prev = prev.next
prev.next = l1 if l1 else l2
return dummy.next
3.2 删除链表倒数第N节点(第19题)
双指针技巧的经典应用:fast指针先走n步,然后和slow指针同步移动。注意使用dummy节点处理删除头节点的情况:
python复制def removeNthFromEnd(head, n):
dummy = ListNode(0, head)
fast = slow = dummy
for _ in range(n + 1):
fast = fast.next
while fast:
slow = slow.next
fast = fast.next
slow.next = slow.next.next
return dummy.next
4. 典型算法思想实战
4.1 二分查找(第35题)
搜索插入位置问题展示了二分查找的模板写法。注意循环条件是left <= right,以及最终返回left的位置:
python复制def searchInsert(nums, target):
left, right = 0, len(nums) - 1
while left <= right:
mid = (left + right) // 2
if nums[mid] == target:
return mid
elif nums[mid] < target:
left = mid + 1
else:
right = mid - 1
return left
4.2 动态规划入门(第53题)
最大子序和问题揭示了动态规划的核心思想——状态转移。定义dp[i]表示以nums[i]结尾的最大和,则有dp[i] = max(nums[i], dp[i-1] + nums[i])。可以优化到O(1)空间:
python复制def maxSubArray(nums):
max_sum = current_sum = nums[0]
for num in nums[1:]:
current_sum = max(num, current_sum + num)
max_sum = max(max_sum, current_sum)
return max_sum
5. 高频易错点与调试技巧
在实现**罗马数字转整数(第13题)**时,常见的错误是忽略减法规则(如IV表示4)。正确的处理方式是当前字符代表数字小于右边时做减法:
python复制def romanToInt(s):
roman = {'I':1, 'V':5, 'X':10, 'L':50, 'C':100, 'D':500, 'M':1000}
total = 0
for i in range(len(s)):
if i < len(s) - 1 and roman[s[i]] < roman[s[i+1]]:
total -= roman[s[i]]
else:
total += roman[s[i]]
return total
对于回文数判断(第9题),转换为字符串的方法虽然简单,但面试官通常期望数学解法。关键点是如何处理数字反转过程中的溢出问题:
python复制def isPalindrome(x):
if x < 0 or (x % 10 == 0 and x != 0):
return False
reverted = 0
while x > reverted:
reverted = reverted * 10 + x % 10
x //= 10
return x == reverted or x == reverted // 10
6. 算法优化进阶思路
以**爬楼梯(第70题)**为例,表面是斐波那契数列问题,实则揭示了多种优化手段。从递归到记忆化搜索,再到动态规划,最后到矩阵快速幂解法:
python复制# 动态规划优化版(O(1)空间)
def climbStairs(n):
if n == 1: return 1
a, b = 1, 2
for _ in range(2, n):
a, b = b, a + b
return b
**合并两个有序数组(第88题)**展示了逆向双指针的妙用。从后向前填充可以避免元素覆盖,时间复杂度O(m+n):
python复制def merge(nums1, m, nums2, n):
p1, p2, p = m-1, n-1, m+n-1
while p1 >= 0 and p2 >= 0:
if nums1[p1] > nums2[p2]:
nums1[p] = nums1[p1]
p1 -= 1
else:
nums1[p] = nums2[p2]
p2 -= 1
p -= 1
nums1[:p2+1] = nums2[:p2+1]
7. 测试用例设计与边界处理
优质的解体需要覆盖各种边界条件。以**实现strStr()(第28题)**为例,需要测试这些场景:
- 空needle应返回0
- needle比haystack长应返回-1
- 部分匹配但最终失败的情况
- 多个匹配位置时应返回第一个索引
KMP算法虽然高效,但面试中更看重正确实现暴力解法。可以先写出暴力解法,再讨论优化方向:
python复制def strStr(haystack, needle):
L, n = len(needle), len(haystack)
for start in range(n - L + 1):
if haystack[start:start + L] == needle:
return start
return -1 if L != 0 else 0
在**外观数列(第38题)**中,递归解法直观但容易在字符串拼接时产生性能问题。使用StringBuilder模式可以显著提升效率:
python复制def countAndSay(n):
s = "1"
for _ in range(n - 1):
temp = []
count = 1
for i in range(1, len(s)):
if s[i] == s[i-1]:
count += 1
else:
temp.append(str(count) + s[i-1])
count = 1
temp.append(str(count) + s[-1])
s = "".join(temp)
return s
8. 从简单题到面试实战的跨越
当你能在15分钟内无bug完成这些"简单题"时,可以尝试以下进阶训练:
- 为每个题目添加详细的注释,解释每个步骤的意图
- 用不同语言实现相同算法(如C++注重指针操作,Java关注接口设计)
- 在白板上手写代码,模拟真实面试场景
- 对每个解法进行时间复杂度分析,并思考优化空间
以**相同的树(第100题)**为例,递归解法简洁但容易忽略None值判断。正确的实现应该先处理节点为空的情况:
python复制def isSameTree(p, q):
if not p and not q:
return True
if not p or not q:
return False
return p.val == q.val and isSameTree(p.left, q.left) and isSameTree(p.right, q.right)
而**对称二叉树(第101题)**则可以转化为两个树的镜像比较问题,需要构建辅助函数:
python复制def isSymmetric(root):
def isMirror(t1, t2):
if not t1 and not t2: return True
if not t1 or not t2: return False
return t1.val == t2.val and isMirror(t1.left, t2.right) and isMirror(t1.right, t2.left)
return isMirror(root, root)
