数组与字符串操作
数组和字符串是面试中最基础也最频繁出现的考点。《程序员面试金典》中特别强调了原地修改(In-place)和双指针技巧的应用。
典型例题:字符串去重
问题描述:实现一个算法,确定一个字符串的所有字符是否全都不同。假使不允许使用额外的数据结构,又该如何处理?
解题思路:
- 方法一:使用位图(BitMap)。由于ASCII字符集有限,可以用一个整数作为位图,遍历字符串,检查对应位是否已置位。
- 方法二:排序后比较。先对字符串进行排序,然后遍历一次检查相邻字符是否相同。时间复杂度为 O(N log N)。
- 方法三:暴力法。双重循环比较,时间复杂度 O(N²),空间复杂度 O(1)。
def isUniqueChars(s):
if len(s) > 128: return False
checker = 0
for char in s:
val = ord(char) - ord('a')
if (checker & (1 << val)) > 0: return False
checker |= (1 << val)
return True
链表与二叉树
链表操作考察指针的熟练度,而二叉树则考察递归思维。CTCI中关于链表分割、回文判断,以及二叉树的遍历、最近公共祖先(LCA)等问题是必考内容。
典型例题:链表回文判断
问题描述:实现一个函数,检查单链表是否为回文链表。
解题思路:
- 递归法:利用递归栈的深度,从链表尾部向前比较,同时维护一个头部指针向后移动。
- 快慢指针+反转:使用快慢指针找到中点,反转后半部分链表,然后双指针同时从头和尾向中间遍历比较。此方法空间复杂度为 O(1)。
动态规划与递归
动态规划(DP)是面试中的难点,也是区分度最高的部分。《程序员面试金典》通过爬楼梯、背包问题变种等经典案例,深入浅出地讲解了状态转移方程的构建。
典型例题:爬楼梯
问题描述:假设你正在爬楼梯。需要 n 阶你才能到达楼顶。每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
解题思路:这是一个经典的斐波那契数列问题。到达第 n 阶的方法数等于到达第 n-1 阶和第 n-2 阶方法数之和。可以使用递归加记忆化搜索,或者迭代法优化空间。
def climbStairs(n):
if n <= 2: return n
dp = [0] (n + 1)
dp[1] = 1
dp[2] = 2
for i in range(3, n + 1):
dp[i] = dp[i-1] + dp[i-2]
return dp[n]