01 前置声明
00 思想准备
01 平常心学习
- 有总比没有好 由于算法本来就是知识点多而且不固定,自己能投入花费的时间是有限的
- 但自己会的知识点还是尽量去做出来,新的知识点和思维方式就可能去理解
- 所以尽自己的努力就最好了,不必要想着自己菜
- 菜就好好努力,不要焦虑,做个解决问题的人
- 有些努力可以获取,有些付出时间与精力也不能获取,做能获取的东西
好好专注知识点和思维方式
做算法题目就是要依靠自己的处理问题思维方式
02 算法花费成本
- 时间成本
//只是一个大概的逻辑估计 简单的题目应该是10-20min解决 中等的题目应该是30min-45min解决
- 要准备的
纸和笔
01 分析与决策
- 题目是什么,你要做什么 -- 将相关要求写在代码前面,将自己的思路也要用文字进行表达
- 问题提出机制 -- 将自己展开的思路遇到短时间解决不了的问题记录下来或者自己解决不了的问题进行记录
02 写代码与修正
-
知识性问题提醒机制 -- 过一个大概的知识流程,起码要发挥自己的实力
-
根据题目编写对应具体测试数据 -- 明确自己要应该达到具体效果
-
具体问题提醒机制 -- 写代码时候进行提醒与修正代码
-
查看知识数据库 -- 开启代码辅助和使用复用代码,减少重复脑力劳动
- 知识数据库 有对知识点的常见思考方式和思维 + 常见代码的问题提醒机制 + 模板代码 + 复用代码
-
排错与修正机制 -- 将自己的代码进行修改或者进行转换思路
- 查看数据的变化,用打印语句,逐步确定哪里错误了
- 编码上的 -- 普遍错误问题提醒机制
- 思维上的 -- 再过一遍整体流程,否则直接参考解答
03 进行验收与复盘
-
基于题目来完善对应知识的问题提醒机制
- 优化大体的知识性问题提醒机制
- 常见思考方式和思维 + 代码的问题提醒机制 + 模板代码 + 复用代码
-
基于迭代的方式进行优化整个流程
- 分清楚什么是学习知识数据库,什么是实践下的知识数据库
02 具体处理
00 个性化声明
自己常犯的两个错误
- 能力不足但又有暴力解决方案,但不想写
一定要逼迫自己做完 有解决方案总比没有解决方案好
比如力扣周赛的443周赛的第二题 30 * 30 * 30 *30
class Solution {
public:
int longestPalindrome(string s, string t) {
//给你两个字符串 s 和 t。
//你可以从 s 中选择一个子串(可以为空)以及从 t 中选择一个子串(可以为空),
//然后将它们 按顺序 连接,得到一个新的字符串。
//返回可以由上述方法构造出的 最长 回文串的长度
//len(1 -- 30)
//1234 2321 =》 1234 321 =》 1234321
//2222 3333 =》 2222 =》 2222
//6555 5557 =》555 555 =》555555
//5556 5557 =》555 555 =》555555
//不知道怎么组合才好
//12342321 =》 123 321
//01232321 =》 123 2321
//我的评价:都第一个题了 既然想出来是暴力 那就打暴力
int ans = 0;
int n = s.size(), m = t.size();
//在一个字符串中从i开始 选用len(j - i + 1)的长度
//长度大于字符串长度没事的
for(int i = 0; i < n; ++i)
for(int j = i - 1; j < n; ++j){
string temp = s.substr(i, j - i + 1);
for(int k = 0; k < m; ++k)
for(int l = k - 1; l < m; ++l){
if(check(temp + t.substr(k, l - k + 1))){
ans = max(ans, (j - i + 1) + (l - k + 1));
}
}
}
return ans;
}
bool check(string s){
int left = 0, right = s.size() - 1;
while(left < right){
if(s[left] != s[right]) return false;
++left;
--right;
}
return true;
}
};
自己害怕时间和空间复杂度过高,导致不往动态规划的方面思考
列数字,找规律
memo = new int[101][10001];//这是灵神给出的答案
数据量一般在十的四次方和十的五次方
//以最小覆盖子串为例子
//m == s.length
//n == t.length
//1 <= m, n <= 10的5次方
class Solution {
public:
bool check(int a[],int b[]){
for(int i='A';i<='Z';i++){
if(a[i]<b[i]) return false;
}
for(int i='a';i<='z';i++){
if(a[i]<b[i]) return false;
}
return true;
}
string minWindow(string s, string t) {
int n=t.size();
int m=s.size();
if(n>m) return "";
//进行答案数组的统计
int ans_left=-1,ans_right=m;
//
int left=0;
int a[128]{},b[128]{};
//b是统计t字符串的字母
for(char c:t){
b[c]++;
}
for(int right=0;right<m;right++){//移动子串右端点
a[s[right]]++;//右端点字母移动子串
//只有a[]有b[]子集才能进入
while(check(a,b)){
//比较区间长度 获取答案长度
if(right-left<ans_right-ans_left){
ans_left=left;
ans_right=right;
}
//进行进行减小
a[s[left++]]--;
}
}
//strsub(起点,长度)
return ans_left<0?"":s.substr(ans_left,ans_right-ans_left+1);
}
};
01 分析与决策阶段
- 代码前面是否放了对应的要求?
- 你的思路是否写了?对应产生的问题又是什么?
- 实在思考不出来,能不能走动去放空,进而更好地思考问题?
- 如果你能直接暴力进行模拟的话?可不可以先模拟,然后再想优化的?
02 写代码与修正
0.做前回答
- 先访问自己有无简单的做法?可以允许不通过,但是一定要把思路打开来
- 做题没思路的前提下,一定要不停的反问自己,给自己提出问题,激活大脑,不断提醒思考
01 知识性问题机制
站在答案的视角,它是怎么样的?
- 可以排除一些特殊用例吗?
- 能不能从答案去反推代码的一些逻辑?真的是从起点才能去解决问题吗?
- 能不能是从后向前开始的吗?
- 要处理的事情是否跟以前的写代码类似的作用?
- 它是过程中得出的答案,还是在处理完数据中得出答案?
- 是否存在环形结构?
他应该使用什么容器来处理数据?
-
自然容器:
- 数组 + 链表(插入方向) +
- 队列(或者两个以上) + 栈(或者两个以上) + 固定哈希(数组进行表示) +
- 有序/无序哈希表(或者两个以上) + 有序/无序集合(或者两个以上) + 有序可以自动排序(可以优化复杂度)
- 二维动态数组(图一般存储) 优先队列
-
数据处理中的容器:
- 线段树(尤其涉及区间修改的地方)
-
根据处理完数据的容器:
- 并查集 + 单调栈/队列 + 并查集
它是应该怎样进行遍历的呢?
- 是从起点出发?还是终点出发?还是中间两端进行遍历的呢?或者是首尾两端进行遍历的?
- 是用for循环,还是while循坏
考虑数据的数值特性没?
- 如果要选择加值,那么应该怎么加?能不能全体都加?或者只加一边?
- 可以使用区间思想吗?
- 数值的增减性? 数据和数据长度的奇偶性? 因数?余数?素数?当前最值?
- 是否考虑到数值的二进制? 运算符号想来没?&^|
是否能批量数据?
- 是选用有序/无序哈希表进行排序?还是基于数组来进行排序呢?
- 是否可以排序?以什么为标准进行排序?
- 如果不能在原数组进行排序,那可以建立以
[nums[i], i]
排序不?ans[arr[i][1]] = 当前值
- 可以用几个指针去处理问题? 字母数值化处理可以不?
- 可不可进行数据分类?
- 能不能将数据进行分组?
是否要记录过程?
- 记录的方向是什么?
- 用数组记录初始或最后的位置? 记录出现的次数?
- 累加累减的前后缀数组?
- 可以使用滑动窗口吗?模拟或记录一个区间?
- 过程中的最值(单调栈, 从小到大或是从大到小)?
kmp
思想?- 可以使用差分数组吗?
- 可以使用BFS吗?
- 是否能使用DP思想?
向下选择过程 -- 即递归?
- DFS? 回溯?
- 记忆化搜索?
有无思考数学处理的观点?
- 能不能推出相关公式?
- 集合论观点去看待问题? 常用哈希表和for遍历在一起使用?
- 组合数学去看待问题?
02 代码修正机制
编码
-
是否数据类型不符合?是否存在运算过程值很大,但结果很小?
int total;(错误的) => long total(正确的);
-
将数字
1
写成字母i
?反之? -
是否是循环条件写错?
//for循环 //起点位置写错?终止条件写错?自变量写错? for (int i = 2; i <= 2; i++) --> for (int i = 2; i <= n; i++) for(int i=1;i<n;i++) --> for(int i=1;i<=n;i++) for(int i=1;i<n;i++) --> for(int i=0;i<26;i++); //while循环 //条件出错误 导致根本没有进入循环之中 //
-
是否写错位置?
//数组下标写错? a[q.back()<a[i]] --> a[q.back()]<a[i]; //还是作用域出错?
-
运算符出错?
// =(不应该的) -> ==(正确的)
-
逻辑顺序出错?
思维
- 是哪种数据没有考虑到?这些数据对应着哪些情况?
- 如果自己的思维根本没有能够处理好这种情况,是否需要直接重新思考一遍?还是直接观看解答?
03 验收与复盘机制
验收 -- 自己的解答和优秀的解答
- 对于自己了解的知识点,有无独立自主编写出代码来?是什么没有做出来?
- 对于自己不了解的知识点,有无总结思想,把流程撰写出来,是否进行了记录?
- 理解别人的代码,你是否做到了宏观思维以及基于宏观思维的具体实现代码?
- 能不能优化整体的做题逻辑?是否能够优化自己的思考方式?
- 是否有启发自己思维的代码?
- 能不能完善问题提醒机制或者整体流程机制?
- 是否有复用的代码?
复盘 -- 将正确的多做,将学习的巩固
- 学习上的方便进行理解与记忆
- 是否做到了进行相关题型分类,将相似的题型进行处理流程化处理,并记忆一些详细处理代码
- 如何落到相关的实处?对具有相同功能的代码[结构 + 处理方式],
- 将其代码进行模板化,将比较好使用的函数进行记录和总结
03 版本迭代
第一版为2025-03-13做到的,简单搭建一个框架
第二版为2025-03-31进行版本迭代,根据个人情况,加入思想准备