📖 动态规划专题怎么用?

动态规划的核心:当前状态只依赖前几个状态。斐波那契、爬楼梯、最大子序和是 DP 的三道入门必刷题。

本专题包含 3 道题,都是外企面试高频真题。每道题按统一结构讲解:

复习建议:先看生活类比理解问题本质,再看思路建立解题框架,最后手写代码 3 遍形成肌肉记忆。面试时先口述思路,确认无误后再写代码。

1斐波那契数列 (Fibonacci) Easy

题目(人话版)

斐波那契数列:0, 1, 1, 2, 3, 5, 8, 13, 21...。规则是每个数 = 前面两个数之和。求第 n 个数。

💡 生活类比:就像你每个月存钱——第一个月存 0,第二个月存 1,之后每个月存的钱 = 上个月存的 + 上上个月存的。随着时间推移,存款越来越多,增长越来越快。

方法一:递归(最直觉但有陷阱)

fib-recursive.js
1
2
3
4
function fib(n) { if (n <= 1) return n; return fib(n - 1) + fib(n - 2); }
递归的致命问题:时间复杂度 O(2ⁿ)!因为 fib(5) 会计算 fib(4)+fib(3),fib(4) 又算 fib(3)+fib(2)……fib(3) 被算了两次,fib(2) 算了三次。指数级爆炸。n=40 时浏览器就要卡好几秒。面试官一定追问"能优化吗?"

方法二:迭代法(面试标准答案)

只记住前两个数,一路往后加。不需要递归,也不需要数组。

fib-iterative.js
1
2
3
4
5
6
7
8
9
10
function fib(n) { if (n <= 1) return n; let prev = 0; // 前一个数(fib(0)) let curr = 1; // 当前数(fib(1)) for (let i = 2; i <= n; i++) { const next = prev + curr; // 下一个 = 前两个之和 prev = curr; // 整体往后挪一步 curr = next; } return curr; }
方法时间空间问题
递归O(2ⁿ)O(n) 栈大量重复计算,n>40 就卡
迭代O(n)O(1)✅ 只记两个变量,又快又省
递归+缓存O(n)O(n)✅ 能写出来是加分项

2爬楼梯 (Climbing Stairs) Easy

题目(人话版)

你在爬楼梯,每次可以爬 1 步或 2 步。爬到第 n 阶有多少种方法?

💡 发现规律:1, 2, 3, 5, 8... 这不就是斐波那契数列吗?!为什么?因为到达第 n 阶只有两种可能:从第 n-1 阶爬 1 步上来,或者从第 n-2 阶爬 2 步上来。所以方法数 = 到 n-1 阶的方法 + 到 n-2 阶的方法。
从第 n-1 阶爬1步 或 从第 n-2 阶爬2步 n-3 n-2 n-1 n 爬1步 爬2步 f(n) = f(n-1) + f(n-2)
到达第 n 阶 = 到 n-1 阶的方法 + 到 n-2 阶的方法
climbStairs.js
1
2
3
4
5
6
7
8
9
10
function climbStairs(n) { if (n <= 2) return n; let prev1 = 1; // 到 n-2 阶的方法数 let prev2 = 2; // 到 n-1 阶的方法数 for (let i = 3; i <= n; i++) { const curr = prev1 + prev2; // f(n) = f(n-1) + f(n-2) prev1 = prev2; prev2 = curr; } return prev2; }

时间 O(n),空间 O(1)。和斐波那契一模一样的迭代写法。

面试加分项:主动说出"这道题本质就是斐波那契数列,可以用动态规划优化到 O(n) 时间 O(1) 空间。" 然后追问"如果每次可以爬 1 步、2 步或 3 步呢?"答案是 f(n) = f(n-1) + f(n-2) + f(n-3)。这种举一反三是面试官最想看到的。

3最大子序和 (Max Subarray) Medium

题目(人话版)

给你一个数组 [-2, 1, -3, 4, -1, 2, 1, -5, 4],找出一个连续的子数组,让它的和最大。答案是 [4, -1, 2, 1],和为 6

💡 生活类比:想象你在记录每天的收支:亏 2、赚 1、亏 3、赚 4、亏 1、赚 2、赚 1、亏 5、赚 4。你想知道连续哪几天的净利润最大。关键决策是:前面的累计利润如果是负数,就干脆"清零重来"——因为带着亏损走不如从头开始。

思路:Kadane 算法(动态规划的简化版)

遍历每个数 前面的累计和 < 0? 丢掉!从当前重新开始
否则 当前数 = 前面累计 + 当前数 更新最大值
maxSubarray.js
1
2
3
4
5
6
7
8
9
10
11
function maxSubArray(nums) { let currSum = nums[0]; // 当前累计和 let maxSum = nums[0]; // 全局最大和 for (let i = 1; i < nums.length; i++) { // 前面累计是负数?丢掉!从当前数重新开始 currSum = Math.max(nums[i], currSum + nums[i]); maxSum = Math.max(maxSum, currSum); } return maxSum; }

模拟过程:[-2, 1, -3, 4, -1, 2, 1, -5, 4]

i当前数前面累计决策currSummaxSum
0-2-初始-2-2
11-2-2<0,丢掉,从1开始11
2-311>0,加上-3-21
34-2-2<0,丢掉,从4开始44
4-144>0,加上-134
5233>0,加上255
6155>0,加上166
7-566>0,加上-516
8411>0,加上456

时间 O(n),空间 O(1)。一次遍历,只用了两个变量。

核心思想:Kadane 算法的精髓就一句话——"前面的累计如果是负数,那带着它走还不如丢掉重来"。这个贪心策略能保证每一步的 currSum 都是"以当前位置结尾的最大子序和"。

📋 动态规划专题速查表

#题目难度
1斐波那契数列 (Fibonacci)Easy
2爬楼梯 (Climbing Stairs)Easy
3最大子序和 (Max Subarray)Medium
考点核心:动态规划专题的核心就是"用对工具,降复杂度"。 面试时拿到题先想:"这道题能用动态规划吗?" 如果能,先说思路再写代码,面试官就知道你的分析能力。

🔗 其他考点专题

双指针专题:回文检测 (Valid Palindrome), 反转字符串 (Reverse String), 合并两个有序数组 (Merge Sorted Arrays), 移动零 (Move Zeroes)

哈希表专题:两数之和 (Two Sum), 有效的字母异位词 (Valid Anagram), 数组去重/判断有重复 (Contains Duplicate), 第一个唯一字符 (First Unique Character)

位运算专题:只出现一次的数字 (Single Number), 缺失数字 (Missing Number)

栈与滑动窗口专题:有效括号 (Valid Parentheses), 最长不重复子串 (Longest Substring)

综合技巧专题:FizzBuzz, 买卖股票的最佳时机 (Best Time to Buy/Sell Stock), 多数元素 (Majority Element), 旋转数组 (Rotate Array), 二分查找 (Binary Search)

← 返回图解算法与模式