算法题到底该怎么刷?高效刷题方法

1、算法题到底该怎么刷?

回答这个问题只需要两个点:一是刷什么题,二是用什么方法刷。

1.1 刷什么题?

首先来回答第一个问题,刷什么题?

  • 《剑指Offer》
  • LeetCode 前200道 + 热题100(这些有高度重合)
  • CodeTop 里按类别可以把前30道题给刷了,部分比较高频的类别比如链表,就可以把出现频次大于20的题都给刷了。

以上题大都有重复,总共估计就300题,甚至不到300题,只要会这些题,应付国内大厂的笔试面试足够了!

我的经验是,不用一直刷新的题目,只要能做到把这200多快300道高频题融会贯通,那么就可以应付笔试足够,应付面试有余了。

资料分享(一些我觉得不错的资料/公众号题解分享)

因为只看一个题解有时候会看不懂,所以不要不要被一段代码所卡住!如果你看不懂的话,可以多找几个讲解的人、博客来看一下,总要有一个人跟你的想法是相似的,脑回路是一样的。下面就列举一下我当时看的一些大佬写的题解,集思广益很重要

  • CodeTop:
  • 代码随想录(必看)
  • liweiwei(weiwei哥写题解真的是不厌其烦,各种细节都掰开了揉碎了给你往嘴里塞)

还有其他我看的一些题解,不多,但他们都或多或少对我有帮助,很感谢这些大佬把业余时间拿出来进行分享。

  • 负雪明烛:
    • gzh:负雪明烛
  • 力扣加加 / lucifer:
    • gzh:力扣加加
    • pdf:去 github 下载
  • labuladong:
    • 公众号:labuladong
    • pdf:我不记得在哪下载了,去公众号上应该能找到
  • 甜姨(写的题解不多,但是很通俗易懂):
    • gzh:甜姨的奇妙冒险
    • leetcode
  • 宫水三叶(三叶姐只在leetcode上写每日一题)

1.2 怎么刷?

刷一道题分三个阶段来看:

  • 第一层:做到“能够根据脑子里这张图把算法的流程用极为精确的语言描述出来,并且画出来那张算法分析的动态图”,其实就是讲思路!并且能够分析不同的算法的时空复杂度!

  • 第二层:“码形结合”的能力,能够根据脑子里这张图把算法的伪代码大致写出来。这里提到一个我自创的名词 “码形结合”,因为也是受到高三做题时的 “数形结合” 的启发,其实写代码有时候也是需要你在心里先有一个数据结构的图,然后根据这张图来把代码实现。比如【回溯算法】的本质其实就是N叉树的遍历,并加上了一些剪枝操作,如果你能在心里把【回溯算法】的N叉数的各个节点的分裂情况给画出来,那么这道题就成功了一半了。

  • 第三层:实现能力,“ 能够不假思索的一边讲思路,一边把代码敲出来并且能够AC”,这个就是面试的最高境界,能一边把整个题的宏观思路给面试官顺下来,一边把题目按你的思路一项一项的去实现。除此之外,还需要有一定的触类旁通思维,能把这道题抽象出来一个算法模型。例如(718. 最长重复子数组)其实就是考察LCS(Longest Common Subsequence)[最长公共子序列问题。

要做到这三点,一道题至少至少要刷三遍,我有的题甚至刷了有五六遍七八遍才能闭着眼AC,例如N个一组反转链表这道题我前前后后得做了有快10遍:

  • 第一遍,记在你的笔记里,想半分钟如果没思路,可以直接看答案,在初期刷题没什么思路时,不要浪费时间,直接看看正确的思路是啥。并且无需拘泥于一个题解,如果一个题解吭哧吭哧半天看不懂,那就换个题解,总要能找到一个思路和你相似、脑回路和你相近的人,迟早会把题搞明白。

  • 第二遍,在本子上画画数据结构的图,写写伪代码,这样做主要是让你的思路清晰,能讲清楚,至少能达到刷题 “第一层” 的境界。

  • 第三遍,直接什么答案都不看,上手编程,熟知考察的重点和实现的细节,以及实现过程中的各种坑。

记笔记很重要,很重要,很重要!主要记录自己的易错点!

  • Leetcode的功能很棒,可以在每次你的提交后面写个备注,比如你这次做错了是因为啥,粗心还是算法没想清楚,都可以记录在leetcode的提交备注功能里。举个例子,如下图所示。
    在这里插入图片描述

  • 手机上的备忘录用起来,在备忘录上的记录不用太详细,主要把算法题的思路、核心点、易错点简单写个轮廓就ok啦!可以地铁上没事也可以刷一刷。
    在这里插入图片描述

  • 刷题的前记后忘现象很常见,不用担心,只要你针对每道题都建立了笔记文档,并且按类别进行归类整理了以后,你要做的只是把这道题的核心点再回顾一下,然后再 “闭着眼睛” 刷一遍就ok了,总要有能记住的那一遍的。

  • 不求一题多解,但求多题一解。其实除了一些比较简单的题可能会问多种解法以外(比如反转链表的递归和迭代两种写法,二叉树遍历的递归和迭代两种写法)。所以抽象思维很重要,把多道题都映射到同一个模型上,举个例子,比如“1035 不相交的线”就可以抽象成 LCS 问题。

2、按分类总结的题

下面把我平时针对每道题的题号收集、博客资料收集的文档都分享给大家。

注意!这个题号并不是说就要全部都刷,因为时间来不及,一定把我上面提到的高频题按分类给刷明白了,如果有余力再把剩下的给刷了!

2.1 双指针 & 滑动窗

袁厨的双指针专题:https://mp.weixin.qq.com/s/C4ZFwyJThBJdyqbNo87isQ
袁厨的题目收集:https://mp.weixin.qq.com/s/raAfG79JZtnuOwvAGE8xMA

双指针:
lc 27 移除元素
lc 209 长度最小的子数组
lc 141 环形链表
lc 142 环形链表
lc 328 奇偶链表
lc 160 相交链表
lc 21 合并两个有序链表
lc 88 合并两个有序数组
lc 15 三数之和
lc 18 四数之和
lc 83 删除排序链表中的重复元素
lc 673. 最长递增子序列的个数
lc 300. 最长递增子序列
1004. 最大连续1的个数 III

最长递增子序列
https://blog.csdn.net/ltrbless/article/details/81318935

滑动窗:
3 无重复字符的最长子串
209 长度最小的子数组
53 最大子序和
84 柱状图中最大的矩形
239 滑动窗口的最大值
424 替换后的最长重复字符
1004 最大连续1的个数 III
1438 绝对差不超过限制的最长连续子数组
5682 lc 周赛 所有子字符串的美丽值
剑指 Offer 41 数据流中位数
剑指 Offer 42 连续子数组的最大和
剑指 Offer 59 滑动窗口的最大值

1.无重复字符的最长子串
2.串联所有单词的子串
3.最小覆盖子串
4.至多包含两个不同字符的最长子串
5.至多包含 K 个不同字符的最长子串
6.长度最小的子数组
7.滑动窗口最大值
8.字符串的排列
9.最小区间
10.最小窗口子序列

2.2 递归 & 二叉树

因为 递归和二叉树总是同时出现,所以放在一起了。

二叉树
lc 144 二叉树的前序遍历(递归 + 迭代 + morris)
lc 94 二叉树的中序遍历(递归 + 迭代 + morris)
lc 145 二叉树的后序遍历(递归 + 迭代 + morris)
lc 110 平衡二叉树
lc 112 路径总和 I
lc 113 路径总和 II
剑指 27 二叉树的镜像
剑指 28 对称的二叉树
剑指 55 二叉树的深度
lc 102 二叉树的层序遍历
lc 98 验证二叉搜索树(中序遍历)
lc 129 求根到叶子节点数字之和
lc 124 二叉树最大路径和
lc 235 二叉搜索树的最近公共祖先
lc 236 二叉树的最近公共祖先
lc 226 翻转二叉树三种方法,DFS 递归、DFS 迭代、BFS 层序
lc 39. 组合总和
lc 46. 全排列
lc 404 左叶子之和
lc 700 二叉搜索树中的搜索
lc 96 不同的二叉搜索树
lc 669 修剪二叉搜索树
lc 106 从中序与后序遍历序列构造二叉树同 剑指 Offer 07 重建二叉树

下面是 weiwei 收集的

作者:liweiwei1419

1.二叉树中的最大路径和
2.二叉树的直径
3.二叉树最长连续序列
4.二叉树中最长的连续序列
5. 最长同值路径
6.二叉树中的最长交错路径
7. 具有所有最深节点的最小子树

2.3 递归 & 回溯

2.3.1 做题套路自我总结

所有回溯递归都是一样的套路,明确递归的对象,对一个节点进行考虑,正如二叉树一样,回溯其就是 N叉树 + 剪枝

  1. 明确递归的对象,要对哪个节点进行递归(二叉树)?还是对一张表的一个格子进行递归(岛屿问题)?还是要对一个状态进行递归(全排列树状图画出来)?
  2. 明确结束条件,到底到什么地方算是结束了,或者说达到什么条件就需要保存一下状态?
  3. 递归工作,该节点如果不满足结束条件,那对它进行一些什么操作,对它连接的节点进行什么操作?如何继续往下分叉?
  4. 返回值,根据递归工作要返回什么值(岛屿面积)?

2.3.2 题目收集

  1. 括号生成
  2. 组合总和
  3. 全排列
  4. 求根到叶子节点数字之和
  5. 路径总和 II
  6. 全排列 II
  7. 三数之和
  8. N 皇后 变态不做了!
  9. 组合总和
  10. 组合总和 II
  11. 全排列
  12. 全排列 II
  13. 组合
  14. 子集
  15. 子集 II
  16. 电话号码的字母组合
  17. 单词搜索

2.4 堆

295 数据流中位数
480 滑动窗口的中位数 ——(难啊 不会)
215 排名前 k 的元素
569 员工薪水中位数??
4 寻找两个正序数组的中位数
347 前 k 个高频元素
703. 数据流中的第 K 大元素
剑指 40: 最小的 k 个数
480 滑动窗中位数 (大根堆 堆排 对顶堆)——(难啊 不会 低频题,不做)

2.5 动态规划

509 斐波那契数
70 爬楼梯
746 使用最小花费爬楼梯
121 买卖股票的最佳时机
122 买卖股票的最佳时机
123 买卖股票的最佳时机
322. 零钱兑换
518. 零钱兑换
64 最小路径和
198 打家劫舍
213 打家劫舍 II
5 最长回文子串
120 三角形最小路径和
lc 673. 最长递增子序列的个数
lc 300. 最长递增子序列
62. 不同路径 ——(中等):路径问题第一讲
63. 不同路径 II ——(中等):路径问题第二讲
64. 最小路径和 ——(中等):路径问题第三讲
120. 三角形最小路径和 ——(中等)
931. 下降路径最小和 ——(中等)
1289 下降路径最小和 II ——(困难)
1575. 统计所有可行路径 ——(困难)
576. 出界的路径数 ——(中等)
1301. 最大得分的路径数目 ——(困难)
647. 回文子串
5. 最长回文子串
718 最长重复子数组
1143 最长重复子序列
678 有效的括号字符串

2.6 贪心算法

45 跳跃游戏II
55 跳跃游戏
435 无重叠子区间
1784 检查二进制字符串字段
1785 构成特定和需要添加的…

2.7 链表

21 合并两个有序链表
23 合并 K 个升序链表
92 反转指定位置链表
25 k 个一组反转链表
61 旋转链表
2 两数相加!!!
19 删除链表倒数第 K 个节点!
19 删除链表的倒数第N个节点——两种实现+图解 中等
21 合并两个有序链表——两种实现+图解 简单
23 合并K个升序链表——四种实现+图解 困难
24 两两交换链表中的节点——三种实现+图解 中等
25 K 个一组翻转链表——两种实现+图解 困难
61 旋转链表——两种实现+图解 中等
82 删除排序链表中的重复元素II ——三种实现+图解 中等
83 删除排序链表中的重复元素 ——两种实现+图解 简单
141 二叉树展开为链表——四种实现+图解 中等
138 复制带随机指针的链表——两种实现+图解 中等
141 环形链表——两种实现+图解 简单
160 相交链表——两种实现+图解 简单
203 移除链表元素 ——两种实现+图解 简单
206 反转链表 ——两种实现+图解 简单
234 回文链表——图解 简单
237 删除链表中的节点 —— 图解 简单
876 链表的中间结点 ——图解 简单
328 奇偶链表

2.8 二分法

图片说明
图片说明

2.9 位运算

137
136
260
645
IP 与整数的互换

2.10 辅助栈

矩阵的最小面积
155 最小栈
739 每日温度
剑指 Offer 59 - II 队列的最大值
剑指 Offer 59 - I 滑动窗口的最大值
lc 239 滑动窗口的最大值
42 接雨水
496 下一个更大元素 I
503 下一个更大元素 II
1081 不同字符的最小子序列

1.接雨水(困难) 暴力解法、优化、双指针、单调栈
2.每日温度(中等) 暴力解法 + 单调栈
3.下一个更大元素 I(简单) 暴力解法、单调栈
4.去除重复字母(困难) 栈 + 哨兵技巧(Java、C++、Python)
5.股票价格跨度(中等) 「力扣」第 901 题:股票价格跨度(单调栈)
6.移掉K位数字
7.最短无序连续子数组

2.11 前缀和

1.子数组异或查询
2.删除排序链表中的重复元素 II

2.12 拓扑排序

1.课程表
2.课程表 II

3、难点攻破

刷题真的很重要,不管是应届求职,还是社招跳槽,都需要体现出一定的算法能力才能过关。
在这里插入图片描述

3.1 动态规划方法 DP

DP的题没有上百道之不能吃透的!

img

如果某一问题有很多重叠子问题,使用动态规划是最有效的。

【所以动态规划中每一个状态一定是由上一个状态推导出来的】,这一点就区分于贪心,贪心没有状态推导,而是从局部直接选最优的,而且很多讲解动态规划的文章都会讲最优子结构和重叠子问题这些,这些东西都是教科书的上定义,晦涩难懂而且不实用。

大家知道动规是由前一个状态推导出来的,而贪心是局部直接选最优的,对于刷题来说就够用了。

算法基本思想

多阶段决策过程:由一系列决策解决问题。每部分决策都决定问题的一种状态,后面的决策所确定的状态只与当前状态有关,而与如何到达当前状态的前过程无关。

最优决策序列:为了达到最优解,当我们从某一状态出发确定后面的决策时,需要枚举后面决策的所有可能序列,从中选择达到最优解的决策序列。(计算量大)

最优化原理(Bellman):最优决策序列具有性质:不论起点选择何处,后面的决策序列必定关于起点状态构成最优决策序列

最优子结构性质:求原问题计算模型的最优解需包含其(相干)子问题的一个最优解。

子问题重叠与备忘录:同样的子问题多次出现,记录第一次计算信息,以备后面调用,节省计算时间。

  • 多段图问题
  • 0/1背包问题
  • 流水线调度问题
  • 最优二叉搜索树问题

动态规划算法设计的基本步骤

1、分析最优解的结构

选定要解决问题的一个计算模型,其具有最优子结构性质

2、建立递推关系式

关于目标值最优值的递推计算公式,有时可能不是一个简单的解析表达式

3、设计求最优值的迭代算法

因为要使用已经处理过的子问题的计算结果,所以采用迭代方法,计算过程中需要保留获取最优解的线索,即记录一些信息。

4、用回溯方法给出最优解

把求最优值算法的计算过程倒回来,借用那里保留的信息就可追溯到最优解。

  1. 确定dp数组(dp table)以及下标的含义
  2. 确定递推公式
  3. dp数组如何初始化
  4. 确定遍历顺序
  5. 举例推导dp数组

【动态规划的递推公式之和前一状态有关,与其他状态无关!!】

做动规的题目,写代码之前一定要把状态转移在dp数组的上具体情况模拟一遍,心中有数,确定最后推出的是想要的结果

然后再写代码,如果代码没通过就打印dp数组,看看是不是和自己预先推导的哪里不一样。

如果打印出来和自己预先模拟推导是一样的,那么就是自己的递归公式、初始化或者遍历顺序有问题了。

如果和自己预先模拟推导的不一样,那么就是代码实现细节有问题。

这样才是一个完整的思考过程,而不是一旦代码出问题,就毫无头绪的东改改西改改,最后过不了,或者说是稀里糊涂的过了

BM63 跳台阶

动规五部曲:

1、确定dp数组以及下标的含义

dp[i]: 爬到第i层楼梯,有dp[i]种方法

2、确定递推公式
在这里插入图片描述

f(n)=f(n-1)+f(n-2)

4、确定遍历顺序

从递推公式dp[i] = dp[i - 1] + dp[i - 2];中可以看出,遍历顺序一定是从前向后遍历的

5、举例推导dp数组

举例当n为5的时候,dp table(dp数组)应该是这样的

70.爬楼梯

public class Solution {
    public int jumpFloor(int target) {
		//递归方式
        //if (target <= 2) return target;
        //return jumpFloor(target-1)+jumpFloor(target-2);

        //迭代方式
        if (target <= 2) return target;
        int res = 0, m = 1, n = 2;
        for (int i = 3; i <= target; i++) {
            res = m + n;
            m = n;
            n = res;
        }
        return res;
    }
}

BM64 最小花费爬楼梯

1、确定dp数组以及下标的含义

dp[i]的定义:到达第i个台阶所花费的最少体力为dp[i]。(注意这里认为是第一步一定是要花费)

对于dp数组的定义,大家一定要清晰!

2、确定递推公式

一定是选最小的,所以dp[i] = min(dp[i - 1], dp[i - 2]) + cost[i];

注意这里为什么是加cost[i],而不是cost[i-1],cost[i-2]之类的,因为题目中说了:每当你爬上一个阶梯你都要花费对应的体力值

3、dp数组如何初始化

根据dp数组的定义,dp数组初始化其实是比较难的,因为不可能初始化为第i台阶所花费的最少体力。

那么看一下递归公式,dp[i]由dp[i-1],dp[i-2]推出,既然初始化所有的dp[i]是不可能的,那么只初始化dp[0]和dp[1]就够了,其他的最终都是dp[0]dp[1]推出。

所以初始化代码为:

vector<int> dp(cost.size());
dp[0] = cost[0];
dp[1] = cost[1];

4、确定遍历顺序

最后一步,递归公式有了,初始化有了,如何遍历呢?

本题的遍历顺序其实比较简单,简单到很多同学都忽略了思考这一步直接就把代码写出来了。

因为是模拟台阶,而且dp[i]又dp[i-1]dp[i-2]推出,所以是从前到后遍历cost数组就可以了。

但是稍稍有点难度的动态规划,其遍历顺序并不容易确定下来

5、举例推导dp数组

拿示例2:cost = [1, 100, 1, 1, 1, 100, 1, 1, 100, 1] ,来模拟一下dp数组的状态变化,如下:

746.使用最小花费爬楼梯

如果大家代码写出来有问题,就把dp数组打印出来,看看和如上推导的是不是一样的。

BM65 最长公共子序列(二)
在这里插入图片描述
Picture1.png
在这里插入图片描述

if s[i] == '(' :
    dp[i] = 0
if s[i] == ')' :
    if s[i - 1] == '(' :
        dp[i] = dp[i - 2] + 2 #要保证i - 2 >= 0
    if s[i - 1] == ')' and s[i - dp[i - 1] - 1] == '(' :
        dp[i] = dp[i - 1] + dp[i - dp[i - 1] - 2] + 2 #要保证i - dp[i - 1] - 2 >= 0

3.2 背包问题

所以背包问题的理论基础重中之重是01背包,一定要理解透!

做动态规划的题目,最好的过程就是自己在纸上举一个例子把对应的dp数组的数值推导一下,然后在动手写代码!

416.分割等和子集1

背包问题(目录)
01背包 : 背包问题 第一讲

【练习】01背包 : 背包问题 第二讲

【学习&练习】01背包 : 背包问题 第三讲

【加餐/补充】01 背包:背包问题 第二十一讲

完全背包 : 背包问题 第四讲

【练习】完全背包 : 背包问题 第五讲

【练习】完全背包 : 背包问题 第六讲

【练习】完全背包 : 背包问题 第七讲

多重背包 : 背包问题 第八讲

多重背包(优化篇)

【上】多重背包(优化篇): 背包问题 第九讲

【下】多重背包(优化篇): 背包问题 第十讲

混合背包 : 背包问题 第十一讲

分组背包 : 背包问题 第十二讲

【练习】分组背包 : 背包问题 第十三讲
多维背包

【练习】多维背包 : 背包问题 第十四讲

【练习】多维背包 : 背包问题 第十五讲

树形背包 : 背包问题 第十六讲

【练习篇】树形背包 : 背包问题 第十七讲

【练习篇】树形背包 : 背包问题 第十八讲

背包求方案数

【练习】背包求方案数 : 背包问题 第十九讲

【练习】背包求方案数 : 背包问题 第十五讲

注:因为之前实在找不到题,这道「求方案数」题作为“特殊”的「多维费用背包问题求方案数」讲过]

背包求具体方案

【练习】背包求具体方案 : 背包问题 第二十讲

泛化背包

【练习】泛化背包


整理不易,关注和收藏后拿走!
欢迎专注我的公众号:AdaCoding 和 Github:AdaCoding123
在这里插入图片描述

  • 35
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
算法提升最快的方法主要是要有系统性的刷题计划和方法。 以下是一些可以帮助你快速提升算法能力的建议: 1. 系统性学习算法和数据结构。首先要掌握一些基本的算法和数据结构,比如排序算法、树、图、堆、队列、栈等等。可以通过读书、看视频、参加培训班等方式来学习。 2. 刷题时要注重思考和总结。刷题不仅仅是为了掌握某个算法或数据结构的实现方法,更重要的是要理解其思想和应用场景。刷题时要注重思考,尝试自己思考算法的时间和空间复杂度,并且要总结归纳每个算法或数据结构的特点和应用场景。 3. 刷题时要注重分类和归纳。要把算法按照目类型和难度进行分类,然后分别针对不同类型的目制定不同的解思路和方法。同时要归纳每种算法的时间和空间复杂度,以便在实际应用时能够快速选择最优算法。 4. 刷题时要注重练习和反复。做算法需要反复练习,不断加深对算法思想的理解和掌握。可以多一些经典目,比如 LeetCode 上的 Top 100 目,同时也可以多一些面试目,包括百度、阿里、腾讯、字节跳动等公司的面试目。 5. 参加算法竞赛和比赛培训。如果有时间和机会,可以参加一些算法竞赛和比赛培训,这样可以接触到更高级别的算法和更复杂的问,同时也可以和其他优秀的程序员进行交流和学习。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值