【LeetCode - 基础题】

感受

统计下来就联系了简单题 30题,中等题21题也没有联系
简单题都练习的费劲
差不多又练习了21天,简单题基本都能cover,中等题有思路也能做的很快

悟道

越往后刷题,发现很多不一样的事情,也多了很多不一样的感受
自己很多思路都很局限,看了别人的思路和解法恍然大悟,拍案叫绝(这些好的思路可固化,为以后刷题所用,不同的思路也可以延伸自己的思维)
有时候真的很累,但是当遇到新的思想,新的思路,学习到之前从未遇到的知识点,整个人是激动的,兴奋的,这种成就感难道不比那些低级趣味更有意思么?或许这也是坚持刷题的意义之一(6.18早上折腾了快2个小时,最终看到别人的题解,那一刻的感受很久没有出现了)
刷题过程中,应该是刷到50题的时候才开始慢慢生成自己的接口模板,才开始总结,总结需要注意的点,总结套路
这些自主的过程当自己认真投入一定的时间,一定的精力后,发现自己开始主动优化总结了,这个过程和之前的考研很类似
当自己积累积累,到了一定程度,才会出现的情况(没有之前的积累,遇到的场景都不多,怎么可能会有后面的优化,区分总结)
不断变聪明,不断高效,有了优化点,有了优化思路的过程,前提是自己得投入大部分的时间,精力才会出现的过程
或者这一点也是坚持去刷题的意义之二
学习是一个由少变多再变少,最开始自己不知道知道的很少,练习的过程中越来越多,这个时候需要去优化总结合并,让繁杂的多变少,掌握精髓
虽然感觉自己练习了很多题,实际上自己没有熟练掌握,很多题都是一个类型的题目,实际有效的题目就那几题。不但总结最终目录下的题目数量也越来越少
一点点分析出来,自己不可能像简单题一样,一眼洞穿,得边思考边写方案
得把思路用语句写下来,怎么去实现,用什么数据结构,提前想好写出来(写不出来就有点危险了)

编译不通过

代码逻辑问题,导致栈为空,还在取st.top
有下标的一定要在纸上把下标推算出来,很多时候折腾下标
堆溢出,下标越界了
注意题目入参参数,const删除
// 注意参数类型,const先删除掉,否则各种奇怪的报错no type named ‘type’ in ‘struct std::enable_if<false, void>’
// passing ‘const std::__cxx11::basic_string’ as ‘this’ argument discards qualifiers [-fpermissive]
代码本来是正常的,还是出现下划线,需要编译一次就正常了(自己在那找了半天的没发现错误)

部分通过(看题一定一定要慢,仔细,每一个限制条件都要看到)

设置目标步数,当前天数之后的步数都会重置
模拟坐标中行走,本来是求所有点中的最大距离,最大没有看到,直接求的最终点的距离
商品打折的问题,也是没有看清条件
题目没看清楚,解题思路都可能不一样,考试不能犯下这些低级错误
一个条件没看仔细,最终很可能都没有办法发现,导致解答一直部分通过
不要因为看错或者看漏条件最后调试没通过
题目限制条件每句话对等翻译出来,多在纸上写一些特殊场景,看能否验证通过(内存池申请释放问题)
只有一个字符的情况
字符全相同的情况,字符全不同的情况
return max(result, len);用例是100%,return result,用例是75%

超出时间限制

for循环中没有i++ i+=2,导致超出时间限制,不一定是代码时间问题,可以使用一个普通的用例调试(先调试)
能不能用空间换时间,而不是嵌套for循环
差分数组的思想
找出数组中两个数的差为给定值的两个数,元素加固定值后在map中查找,而不是嵌套for
for循环中包含if break,break会跳出for循环
if continue,continue会继续执行for循环,两种情况都不会执行后续代码
超时 部分用例通过
先优化,优化也没有生效,那一定是做题的思路错了,不要一个思路调试到底,得变通

做题策略

考的是工作级,先做最后一题,最后一题如果部分通过还是很危险,还不如把最后一题全部通过安心做前面两题,不通过大概率还是过不了
平时练题的过程中,部分通过的用例也要特别注意了,没过的场景得自己总结出来,避免考试实际采坑
考试提前确认远程是否正常,耽误的15分钟也是时间,也很影响自己的状态(在会议室也能安心做题)
很喜欢考多个数组,某个数组有多个元素的情况,看到的一瞬间,还在纠结怎么去取元素
做题时间也很重要,做题不能懒懒散散,做几天可能又开始飘了,又开始有自信了
封装做的还不够好,封装的越好,考试中花的时间越少
没有思路不要coding,,首先得保证框架对,debug在所难免
本来以为自己复习的很好了,可是在别人看来,很容易的题目自己都做不出来

调试

调试:跳转不正常花了很多时间在步骤验证上,没有考虑解题思路是否正确,调试问题得解决
跳转问题,得通过用例搞清楚
该句走完才能看到下一步结果
每题题构造的用例一起拷贝下来!!!

小技巧

比较大小直接用函数,不要用三目运算, 多用max / min
接口复用,小模块的接口能做到直接复用
做不出来的题目,已有代码不要直接删掉,注释即可,可能改着改着,发现原来的代码问题,可是被自己已经删掉了,然后一步步回退,这得多耽误时间
新思路,重新写代码
有些题目考察的点得把握准字符串的有些题目可能出题者是想考察正则表达式,而你虽然可以花很多时间写出来,但是没有任何意义
临时变量赋值有点问题!!!定义pre,计算当前cur,当前赋值给pre

设计题

先直接拷贝验证,一次过的概率应该很小
完善输入,单步看什么地方有问题,一定一定一定不要在LeetCode上修改!!!时间浪费了,还来回复制
只能自己多构造写用例,一点点尝试了(选取的数据结构不同,代码思路完全不一样)
5.13挂在滑动窗口,6.10挂在设计题
手动补充用例,不要改一次复制一次提交一次,来回修改容易忘记,也浪费时间(本地调试好,再粘贴)
优先使用 <= >=,不加=需要多余的计算,容易出错
使用!isdigit(),不容易出错,特殊符号的场景可能考虑不到
求数组最大值,可以先排序,再取头元素 // 很多题目都适合这种方法
很喜欢考察这样的套路,先把所有结果都计算出来再从其中找到符合要求的解
两个数组,找数组对(不可重复),让数组对的和最小(自己:直接求两个数组的最小值处理) -> 嵌套for循环遍历,排序
IP地址:给定字符串,输出所有排列满足0-255范围的串,可重复(自己:二叉树获取所有结果)-> 直接遍历0-255,输出满足的字符串
字符串的题目乍一看很多限制条件,很多校验条件,细节关注过多导致正常流程的代码来回纠结,浪费时间
先把正常流程的架子写出来
在把特殊校验穿插其中(框架出来了,特殊校验其实穿插的地方就很明确了),先写架子,先写架子,先写架子!!!

看清题目
1、题目都说了元素唯一,就不需要再用set,直接用map,多一个条件解法都不一样!
2、界面放大,条件看清楚
3、所有用例都要看完(有些用例可能是特殊解,对代码逻辑判断至关重要,少些一个条件可能少一半的用例通过)

  1. 一定一定要多看书,这个是工作下班之余一定要有的学习过程,早上看书看到了滑窗,联想到之前自己没有思路的题目,发现可以用滑窗解决。有输入,才可能有输出,好的思路,方法,思想都可以从书本中学习到
  2. 练题过程中越发觉得,那些厉害的人,多半都是有一套自己的解题模板,就像东哥已经给我总结出的模板一样,或许当自己能总结出这种模板供以后的工作学习复用,节省大量时间,提高效率的时候,才是人生的光明时刻啊!!!

推荐练习题目
字符串:
https://leetcode-cn.com/problems/decode-string/

二分查找算法练习题:
https://leetcode-cn.com/problems/capacity-to-ship-packages-within-d-days/
https://leetcode-cn.com/problems/find-in-mountain-array/solution/shan-mai-shu-zu-zhong-cha-zhao-mu-biao-zhi-by-leet/
https://leetcode-cn.com/problems/koko-eating-bananas/
https://leetcode-cn.com/problems/find-first-and-last-position-of-element-in-sorted-array/

双指针技巧练习题:
https://leetcode-cn.com/problems/3sum-closest/
https://leetcode-cn.com/problems/fruit-into-baskets/

滑动窗算法练习题:
https://leetcode-cn.com/problems/longest-substring-without-repeating-characters
https://leetcode-cn.com/problems/maximum-points-you-can-obtain-from-cards
https://leetcode-cn.com/problems/find-all-anagrams-in-a-string/submissions/
https://leetcode-cn.com/problems/minimum-window-substring/
https://leetcode-cn.com/problems/max-consecutive-ones-iii/submissions/

BFS算法练习题:
https://leetcode-cn.com/problems/open-the-lock/
https://leetcode-cn.com/problems/surrounded-regions/
https://leetcode-cn.com/problems/as-far-from-land-as-possible/
https://leetcode-cn.com/problems/longest-increasing-path-in-a-matrix/

DFS算法练习题:
https://leetcode-cn.com/problems/reconstruct-itinerary/
https://leetcode-cn.com/problems/generate-parentheses/
https://leetcode-cn.com/problems/course-schedule/
https://leetcode-cn.com/problems/word-search/

单调栈练习题:
https://leetcode-cn.com/problems/daily-temperatures/

元素首次出现/最后一次出现的索引

// 入参字符char
int firstIndex = str.find_first_of(cha);
int lastIndex = str.find_last_of(cha);

npos(一个常数,表示不存在)
find可查找字符,也可以查找字符串

s.find("abcdefg") == string::npos // 同样适用find_first_of和find_last_of

字符串解码

找大写字母的位置
输入:str = “MyNameIsTom”
输出:“yMemaNsImoT”
解释:str中的单词为”My”,“Name”,“Is”,“Tom”
滑动窗口也能解此题,但是滑动窗口最后一个字符串没能取出来(两个字符才会把子串存入)

        // 窗口只能有一个大写字符
        int left = 0;
        int right = 0;
        int upCount = 0;

        vector<string> vec;
        while (right < word.size()) {
            if (word[right] <= 'Z') {
                upCount++;
            }
            
            
            if (upCount == 2) {
                string subStr = word.substr(left, right - left); // 是长度而不是索引,考试紧张这个地方会出错
                reverse(subStr.begin(), subStr.end());
                vec.push_back(subStr);
                left = right;
                upCount = 0; // 减1有问题,下次从Name开始遍历,upCout为1
                continue;  
            }
            right++;
        }

        // 最后一个字符串没有取出来
        string resStr = "";
        for (auto ele : vec) {
            resStr += ele;
        }

找大写字母索引,存入vector
字符串操作本质就是在操作索引,如果题目能确定每一个索引,逻辑和代码思路会简单很多(优先获取索引!!!)

        vector<int> indexVec;
        for (int i = 0; i < word.size(); i++) {
            if (word[i] <= 'Z') {
                indexVec.push_back(i);
            }
        }

        string resStr = "";
        for (int i = 0; i < indexVec.size(); i++) {
            string subStr = word.substr(indexVec[i], indexVec[i + 1] - indexVec[i]);
            reverse(subStr.begin(), subStr.end());

            resStr += subStr;
        }
        return resStr;

https://leetcode-cn.com/problems/zigzag-conversion/
思想很重要,自己思路很局限,花了一个多小时发现解出来有问题
只需要三个字符串来维护,看了别人的题解,感觉自己的思路和想法有点太low了
在这里插入图片描述
使用flag标志位,flag = -flag 从上往下切到从下往上

不同数据结构遍历

数组
在这里插入图片描述
map
map.count(key) 统计key是否存在,所以只会是1或0(不会出现重复的key)
map和set两种容器的底层结构都是红黑树,所以容器中不会出现相同的元素,因此count()的结果只能为0和1,可以以此来判断键值元素是否存在
map.count(key) :只是判断key是否存在,不需要拿到key对应的值
map.find():返回迭代器,获取key对应值
在这里插入图片描述
遍历map是无法渠道索引,需要通过变量确定当前索引

    int getRandom() {
        int randomIndex = rand()%mp.size();
        int count = 0;
        int res = 0;
        for (auto ele : mp) {
            if (count == randomIndex) {
                res = ele.first;
                break;
            }
            count++;
        }
        return res;
    }

字符串

字符串分割,提取接口

int main()
{
	string str;	
	string str_cin("one#two#three");
	stringstream ss;
	ss << str_cin;
	while (getline(ss, str, '#'))
		cout << str<< endl;
	system("pause");
	return 0;
}

得到的结果为

one
two
three

在这里插入图片描述
两个空格之间str = “”,输出时加一个判断 str.empty()

输入:buttons = "zyxwvutsrqponmlkjihgfedcba", word = "xyz"
输出:4
解释:
机械手从0号键移动到2号键来输出’x’,又移动到1号键来输出’y’,接着移动到0号键来输出’z’。总用时 = 2 + 1 + 1 = 4class Solution {
public:
    int caculateTime(string keyboard, string word)
    {
        // 思路很重要,选择那种数据结构也很重要
        // 将word的索引找出存入到vec  将keyboard的元素存入map,直接通过可以确定索引,不需要每个元素去遍历(元素唯一,优先使用map)
        vector<int> vec;
        for (auto w : word) {
            for (int i = 0; i < keyboard.size(); i++) {
                if (w == keyboard[i]) {
                    vec.push_back(i + 1);
                }
            }
        }

        int sum = vec[0] - 1;
        for (int i = 0; i < vec.size() - 1; i++) {
            sum += abs(vec[i] - vec[i + 1]);
        }

        return sum;
    }
};

二维数组操作

  1. 数组旋转
    先对角线交换元素,在reverse每一行即可得到顺时针90°或逆时针90°变换后的数组
    在这里插入图片描述
using namespace std;
class Solution {
public:
    void rotate(vector<vector<int>>& matrix) {
        int len = matrix.size();
        for (int i = 0; i < len; i++) {
            for (int j = i + 1; j < len; j++) {
                int tmp = matrix[i][j];
                matrix[i][j] = matrix[j][i];
                matrix[j][i] = tmp;
            }
        }

        int row = 0;
        for (auto ele : matrix) {
            reverse(ele.begin(), ele.end());
            
            for (int i = 0; i < ele.size(); i++) {
                matrix[row][i] = ele[i];
                cout << ele[i] << endl;
            }

            row++; // 位置放错,放到for循环中了(变量是放在循环中还是放在循环外,变量是在循环之前自加还是在循环之后自加)
        }

    }
};
  1. 数组花式遍历
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值