算法面试通关 40 讲
覃超
Sophon Tech 创始人,前 Facebook 工程师,卡内基梅隆大学计算机硕士
78356 人已学习
新⼈⾸单¥68
课程目录
已完结/共 62 讲
第二章:理论讲解+面试题实战 (53讲)
算法面试通关 40 讲
登录|注册
留言
36
收藏
沉浸
阅读
分享
手机端
回顶部
当前播放: 46 | 面试题:三角形的最小路径和
00:00 / 00:00
高清
  • 高清
1.0x
  • 2.0x
  • 1.5x
  • 1.25x
  • 1.0x
  • 0.75x
  • 0.5x
网页全屏
全屏
00:00
付费课程,可试看
01 | 合格程序员的第一步:算法与数据结构
02 | 如何事半功倍地学习算法与数据结构
03 | 如何计算算法的复杂度
04 | 如何通过LeetCode来进行算法题目练习
05 | 理论讲解:数组&链表
06 | 面试题:反转一个单链表&判断链表是否有环
07 | 理论讲解:堆栈&队列
08 | 面试题:判断括号字符串是否有效
09 | 面试题:用队列实现栈&用栈实现队列
10 | 理论讲解:优先队列
11 | 面试题:返回数据流中的第K大元素
12 | 面试题:返回滑动窗口中的最大值
13 | 理论讲解:哈希表
14 | 面试题:有效的字母异位词
15 | 面试题:两数之和
16 | 面试题:三数之和
17 | 理论讲解:树&二叉树&二叉搜索树
18 | 面试题:验证二叉搜索树
19 | 面试题:二叉树&二叉搜索树的最近公共祖先
20 | 理论讲解:二叉树遍历
21 | 理论讲解:递归&分治
22 | 面试题:Pow(x,n)
23 | 面试题:求众数
24 | 理论讲解:贪心算法
25 | 面试题:买卖股票的最佳时机
26 | 理论讲解:广度优先搜索
27 | 理论讲解:深度优先搜索
28 | 面试题:二叉树层次遍历
29 | 面试题:二叉树的最大和最小深度
30 | 面试题:生成有效括号组合
31 | 理论讲解:剪枝
32 | 面试题:N皇后问题
33 | 面试题:数独问题
34 | 理论讲解:二分查找
35 | 面试题:实现一个求解平方根的函数
36 | 理论讲解:字典树
37 | 面试题:实现一个字典树
38 | 面试题:二维网格中的单词搜索问题
39 | 理论讲解:位运算
40 | 面试题:统计位1的个数
41 | 面试题:2的幂次方问题&比特位计数问题
42 | 面试题:N皇后问题的另一种解法
43 | 理论理解:动态规划(上)
44 | 理论理解:动态规划(下)
45 | 面试题:爬楼梯
46 | 面试题:三角形的最小路径和
47 | 面试题:乘积最大子序列
48 | 面试题:股票买卖系列
49 | 面试题:最长上升子序列
50 | 面试题:零钱兑换
51 | 面试题:编辑距离
52 | 理论讲解:并查集
53 | 面试题:岛屿的个数&朋友圈(上)
54 | 面试题:岛屿的个数&朋友圈(下)
55 | 理论讲解: LRU Cache
56 | 面试题:设计和实现一个LRU Cache缓存机制
57 | 理论讲解:布隆过滤器
58 | 课程重点回顾
59 | FAQ答疑&面试中切题四件套
60 | 回到起点:斐波拉契数列
61 | 白板实战番外篇:斐波拉契数列
62 | 结课测试&最后的一些经验分享
登录 后留言

全部留言(36)

  • 最新
  • 精选
DanielAnton
想法有了,但自己写折腾了好久,还是练的太少了,贴出来,有改进的地方希望提出来,大家共同学习~~ 自顶向下: ``` public int minimumTotal(List<List<Integer>> triangle) { int level = triangle.size(); return helper(triangle, 0, 0, level); } // 参数i表示当前层,level表示共有多少层 public int helper(List<List<Integer>> triangle, int i, int j, int level) { if(i >= level || j >= triangle.get(i).size()) return 0; int left = helper(triangle, i + 1, j, level); int right = helper(triangle, i + 1, j + 1, level); return Math.min(left, right) + triangle.get(i).get(j); } ``` 带备忘录的自顶向下: ``` public static int minimumTotal(List<List<Integer>> triangle) { int level = triangle.size(); List<List<Integer>> memory = new ArrayList<>(); memory.add(new ArrayList<>()); return helper(triangle, 0, 0, level, memory); } // 参数i表示当前层,level表示共有多少层 public static int helper(List<List<Integer>> triangle, int i, int j, int level, List<List<Integer>> memory) { if(i >= level || j >= triangle.get(i).size()) return 0; // 到了最后一层,就将结果全部放入 if(i == level - 1 && memory.get(i).isEmpty()) { for(int k = 0; k < triangle.get(i).size(); k++) memory.get(i).add(triangle.get(i).get(k)); } if(!memory.get(i).isEmpty() && j < memory.get(i).size() && memory.get(i).get(j) != null) return memory.get(i).get(j); if(memory.size() < level) // 防止添加回溯的过程又添加 memory.add(new ArrayList<>()); int left = helper(triangle, i + 1, j, level, memory); int right = helper(triangle, i + 1, j + 1, level, memory); memory.get(i).add(Math.min(left,right) + triangle.get(i).get(j)); return memory.get(i).get(j); } ```

作者回复: 这种努力学习和动手的态度值得表扬!!

2019-04-04
3
Sun0010
老师讲的非常好,动态倒推的3部曲 1. 定义状态 dp[i][j] : 从底部到 triangel[i][j] 的路径的最小值 2.转移方程式: dp[i][j] = triangle[i][j] + min(dp[i+1][j],dp[i+1][j+1]); 3.定义初始化的值: dp[rowMax][j] = triangle[rowMax][j] 我总感觉用二维数组存储更好理解,老师的代码里面是用 一维数组存储 最小值,感觉很N,但对于初学者 有点 看不太懂 for (int i = rowMax-1; i >=0 ; i--) { for (int j = 0; j <=colMax && triange[i][j] >0 (假设 0是初始值) ;j ++ ) { dp[i][j] = triangle[i][j] + min(dp[i+1][j],dp[i+1][j+1]); } } return dp[0][0];

作者回复: 对的,你用二维数组非常清晰。不过就是一维数组的好处是稍微节省内存。

2018-12-02
2
DanielAnton
留言长度限制,只有分开了,这是动态规划的 动态规划: ``` public static int minimumTotal(List<List<Integer>> triangle) { int level = triangle.size(); List<Integer> min = new ArrayList<>(triangle.get(level - 1)); for(int i = level - 2; i >= 0; i--) { int len = triangle.get(i).size(); for(int j = 0, k = 0; j < len && k < len; j++, k++) { int tmp = Math.min(min.get(k), min.get(k + 1)) + triangle.get(i).get(j); min.set(j, tmp); } min.remove(min.size() - 1); // 每次重置后,最后一个就不需要了 } return min.get(0); } ```

作者回复: 赞👍

2019-04-04
邓桥
老师,我自己怎么是从上到下递推的,这样有问题吗?

作者回复: 上到下没法有效递推吧

2018-12-16
joy
老师讲的很好,看了两遍动态规划这个系列,动态规划突然开窍了,感觉这个算法太牛了
2018-12-30
1
20
WWLynn
这些算法,都不是一遍就能看懂的,得看好几遍
2020-03-28
15
张亚运
动态规划可以理解自己一生的路都已知,然后从死到生再走一遍吗?
2020-02-01
1
10
Don
老师讲得思想方法很重要,递归--》存储--》递推 现在看到能递归的就反着想,然后找上一步能保存到下一步的数据结构,越简单的越好。
2018-12-24
8
雷朝建
写这道题时候, 我还没学习过动态规划, 然后我从上往下写, 但明显代码没有从下往上优美。 JS版本(从上往下): /** * @param {number[][]} triangle * @return {number} */ var minimumTotal = function(triangle) { for (let i = 1; i < triangle.length; i++) { for (let j = 0; j < triangle[i].length; j++) { const prev = triangle[i - 1]; const cur = triangle[i]; if (j === 0) triangle[i][j] += prev[0]; else if (j === cur.length - 1) triangle[i][j] += prev[prev.length - 1]; else triangle[i][j] += Math.min(prev[j - 1], prev[j]); } } return Math.min(...triangle[triangle.length - 1]); }; JS版本(从下往上): /** * @param {number[][]} triangle * @return {number} */ var minimumTotal = function(triangle) { const mini = triangle[triangle.length - 1]; for (let i = triangle.length - 2; i >= 0; i--) { for (let j = 0; j < triangle[i].length; j++) { mini[j] = triangle[i][j] + Math.min(mini[j], mini[j + 1]); } } return mini[0]; }; 被mini数组的设定震惊到了。
2019-01-12
1
5
递归和递推的概念终于理解的比较清楚了,感谢!
2020-03-27
2
收起评论