diff --git a/README.md b/README.md index 567b362b..de678054 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,3 @@ -## 重要通知! - -攻略里每篇文章都是公众号的文章链接,之前是为了方便,可随着star和fork的同学越来越多,发现文章链接的话没有办法及时修改题解,大家也没法参与进来,所以近期我会陆续将题解换回Markdown文件。 - -感谢每一位star和fork的同学,LeetCode-Master将越来越好,不负期待! - ## 一些闲话: > 1. **介绍**:本项目是一套完整的刷题计划,旨在帮助大家少走弯路,循序渐进学算法,[关注作者](#关于作者) @@ -23,27 +17,6 @@

-

- - - - - -# B站算法视频讲解 - -以下为[B站「代码随想录」](https://space.bilibili.com/525438321)算法讲解视频: - -* [帮你把KMP算法学个通透!(理论篇)](https://www.bilibili.com/video/BV1PD4y1o7nd) -* [帮你把KMP算法学个通透!(代码篇)](https://www.bilibili.com/video/BV1M5411j7Xx) -* [带你学透回溯算法(理论篇)](https://www.bilibili.com/video/BV1cy4y167mM) -* [回溯算法之组合问题(力扣题目:77.组合)](https://www.bilibili.com/video/BV1ti4y1L7cv) -* [组合问题的剪枝操作(对应力扣题目:77.组合)](https://www.bilibili.com/video/BV1wi4y157er) -* [组合总和(对应力扣题目:39.组合总和)](https://www.bilibili.com/video/BV1KT4y1M7HJ/) -* [分割回文串(对应力扣题目:131.分割回文串)](https://www.bilibili.com/video/BV1c54y1e7k6) -* [关于二叉树,你该了解这些!(理论基础一网打尽)](https://www.bilibili.com/video/BV1Hy4y1t7ij) - -(持续更新中....) - # LeetCode 刷题攻略 ## 刷题攻略的背景 @@ -86,6 +59,7 @@ 准备好了么,刷题攻略开始咯,go go go! +--------------------------------------------- ## 前序 @@ -96,9 +70,9 @@ * [C++面试&C++学习指南知识点整理](https://github.com/youngyangyang04/TechCPP) * 编程素养 - * [看了这么多代码,谈一谈代码风格!](https://mp.weixin.qq.com/s/UR9ztxz3AyL3qdHn_zMbqw) - * [力扣上的代码想在本地编译运行?](https://mp.weixin.qq.com/s/r1696t8lvcw7Rz4gb_jacw) - * [什么是核心代码模式,什么又是ACM模式?](https://mp.weixin.qq.com/s/TSEBJoeCB0dVVXFnlmES3A) + * [看了这么多代码,谈一谈代码风格!](./problems/看了这么多代码,谈一谈代码风格!.md) + * [力扣上的代码想在本地编译运行?](./problems/力扣上的代码想在本地编译运行?.md) + * [什么是核心代码模式,什么又是ACM模式?](./problems/什么是核心代码模式,什么又是ACM模式?.md) * 工具 * [一站式vim配置](https://github.com/youngyangyang04/PowerVim) * [保姆级Git入门教程,万字详解](https://mp.weixin.qq.com/s/Q_O0ey4C9tryPZaZeJocbA) @@ -253,7 +227,7 @@ 6. [本周小结!(回溯算法系列一)](./problems/周总结/20201030回溯周末总结.md) 7. [回溯算法:求组合总和(二)](./problems/0039.组合总和.md) 8. [回溯算法:求组合总和(三)](./problems/0040.组合总和II.md) -9. [回溯算法:分割回文串](https://mp.weixin.qq.com/s/Pb1epUTbU8fHIht-g_MS5Q) +9. [回溯算法:分割回文串](./problems/0131.分割回文串.md) 10. [回溯算法:复原IP地址](https://mp.weixin.qq.com/s/v--VmA8tp9vs4bXCqHhBuA) 11. [回溯算法:求子集问题!](https://mp.weixin.qq.com/s/NNRzX-vJ_pjK4qxohd_LtA) 12. [本周小结!(回溯算法系列二)](https://mp.weixin.qq.com/s/uzDpjrrMCO8DOf-Tl5oBGw) @@ -408,6 +382,21 @@ 1. [选择方向的时候,我也迷茫了](https://mp.weixin.qq.com/s/ZCzFiAHZHLqHPLJQXNm75g) 2. [刷题就用库函数了,怎么了?](https://mp.weixin.qq.com/s/6K3_OSaudnHGq2Ey8vqYfg) +# B站算法视频讲解 + +以下为[B站「代码随想录」](https://space.bilibili.com/525438321)算法讲解视频: + +* [帮你把KMP算法学个通透!(理论篇)](https://www.bilibili.com/video/BV1PD4y1o7nd) +* [帮你把KMP算法学个通透!(代码篇)](https://www.bilibili.com/video/BV1M5411j7Xx) +* [带你学透回溯算法(理论篇)](https://www.bilibili.com/video/BV1cy4y167mM) +* [回溯算法之组合问题(力扣题目:77.组合)](https://www.bilibili.com/video/BV1ti4y1L7cv) +* [组合问题的剪枝操作(对应力扣题目:77.组合)](https://www.bilibili.com/video/BV1wi4y157er) +* [组合总和(对应力扣题目:39.组合总和)](https://www.bilibili.com/video/BV1KT4y1M7HJ/) +* [分割回文串(对应力扣题目:131.分割回文串)](https://www.bilibili.com/video/BV1c54y1e7k6) +* [关于二叉树,你该了解这些!(理论基础一网打尽)](https://www.bilibili.com/video/BV1Hy4y1t7ij) + +(持续更新中....) + # 关于作者 大家好,我是程序员Carl,哈工大师兄,ACM 校赛、黑龙江省赛、东北四省赛金牌、亚洲区域赛铜牌获得者,先后在腾讯和百度从事后端技术研发,CSDN博客专家。对算法和C++后端技术有一定的见解,利用工作之余重新刷leetcode。 diff --git a/pics/公众号.png b/pics/公众号.png index 9873ef42..eeec00ad 100644 Binary files a/pics/公众号.png and b/pics/公众号.png differ diff --git a/problems/0017.电话号码的字母组合.md b/problems/0017.电话号码的字母组合.md index 0743ed9b..6b3a9bf7 100644 --- a/problems/0017.电话号码的字母组合.md +++ b/problems/0017.电话号码的字母组合.md @@ -239,5 +239,4 @@ public: * B站:[代码随想录](https://space.bilibili.com/525438321) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) -![](https://img-blog.csdnimg.cn/20210416110157800.png) - +![](../pics/公众号.png) diff --git a/problems/0027.移除元素.md b/problems/0027.移除元素.md index 3e4a68e0..213b1e6d 100644 --- a/problems/0027.移除元素.md +++ b/problems/0027.移除元素.md @@ -121,4 +121,5 @@ public: * B站:[代码随想录](https://space.bilibili.com/525438321) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) -![](https://img-blog.csdnimg.cn/20210416110157800.png) +![](../pics/公众号.png) + diff --git a/problems/0035.搜索插入位置.md b/problems/0035.搜索插入位置.md index 572b7a37..4dff4c6a 100644 --- a/problems/0035.搜索插入位置.md +++ b/problems/0035.搜索插入位置.md @@ -204,6 +204,6 @@ public: * B站:[代码随想录](https://space.bilibili.com/525438321) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) -![](https://img-blog.csdnimg.cn/20210416110157800.png) +![](../pics/公众号.png) diff --git a/problems/0039.组合总和.md b/problems/0039.组合总和.md index ecec542e..4121d41d 100644 --- a/problems/0039.组合总和.md +++ b/problems/0039.组合总和.md @@ -233,4 +233,6 @@ public: * B站:[代码随想录](https://space.bilibili.com/525438321) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) -![](https://img-blog.csdnimg.cn/20210416110157800.png) +![](../pics/公众号.png) + + diff --git a/problems/0040.组合总和II.md b/problems/0040.组合总和II.md index 24780a92..8957bc2a 100644 --- a/problems/0040.组合总和II.md +++ b/problems/0040.组合总和II.md @@ -253,4 +253,5 @@ public: * B站:[代码随想录](https://space.bilibili.com/525438321) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) -![](https://img-blog.csdnimg.cn/20210416110157800.png) +![](../pics/公众号.png) + diff --git a/problems/0077.组合.md b/problems/0077.组合.md index 7cab9127..1a65beb6 100644 --- a/problems/0077.组合.md +++ b/problems/0077.组合.md @@ -30,10 +30,6 @@ ## 思路 -> 可以直接看我的B栈视频讲解: -> [带你学透回溯算法-组合问题](https://www.bilibili.com/video/BV1ti4y1L7cv) -> [带你学透回溯算法-组合问题的剪枝操作](https://www.bilibili.com/video/BV1wi4y157er) - 本题这是回溯法的经典题目。 @@ -342,6 +338,5 @@ public: * B站:[代码随想录](https://space.bilibili.com/525438321) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) -![](https://img-blog.csdnimg.cn/20210416110157800.png) - +![](../pics/公众号.png) diff --git a/problems/0077.组合优化.md b/problems/0077.组合优化.md index e4532c01..1f9d261e 100644 --- a/problems/0077.组合优化.md +++ b/problems/0077.组合优化.md @@ -11,6 +11,8 @@ 在[回溯算法:求组合问题!](https://mp.weixin.qq.com/s/OnBjbLzuipWz_u4QfmgcqQ)中,我们通过回溯搜索法,解决了n个数中求k个数的组合问题。 +> 可以直接看我的B栈视频讲解:[带你学透回溯算法-组合问题的剪枝操作](https://www.bilibili.com/video/BV1wi4y157er) + 文中的回溯法是可以剪枝优化的,本篇我们继续来看一下题目77. 组合。 链接:https://leetcode-cn.com/problems/combinations/ @@ -142,6 +144,6 @@ public: * B站:[代码随想录](https://space.bilibili.com/525438321) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) -![](https://img-blog.csdnimg.cn/20210416110157800.png) +![](../pics/公众号.png) diff --git a/problems/0131.分割回文串.md b/problems/0131.分割回文串.md new file mode 100644 index 00000000..d382cad4 --- /dev/null +++ b/problems/0131.分割回文串.md @@ -0,0 +1,251 @@ + +

+ + + + +

+> 切割问题其实是一种组合问题! + +## 131.分割回文串 + +题目链接:https://leetcode-cn.com/problems/palindrome-partitioning/ + +给定一个字符串 s,将 s 分割成一些子串,使每个子串都是回文串。 + +返回 s 所有可能的分割方案。 + +示例: +输入: "aab" +输出: +[ + ["aa","b"], + ["a","a","b"] +] + + +## 思路 + +关于本题,大家也可以看我在B站的视频讲解:[131.分割回文串(B站视频)](https://www.bilibili.com/video/BV1c54y1e7k6) + +本题这涉及到两个关键问题: + +1. 切割问题,有不同的切割方式 +2. 判断回文 + +相信这里不同的切割方式可以搞懵很多同学了。 + +这种题目,想用for循环暴力解法,可能都不那么容易写出来,所以要换一种暴力的方式,就是回溯。 + +一些同学可能想不清楚 回溯究竟是如果切割字符串呢? + +我们来分析一下切割,**其实切割问题类似组合问题**。 + +例如对于字符串abcdef: + +* 组合问题:选取一个a之后,在bcdef中再去选取第二个,选取b之后在cdef中在选组第三个.....。 +* 切割问题:切割一个a之后,在bcdef中再去切割第二段,切割b之后在cdef中在切割第三段.....。 + +感受出来了不? + +所以切割问题,也可以抽象为一颗树形结构,如图: + +![131.分割回文串](https://code-thinking.cdn.bcebos.com/pics/131.%E5%88%86%E5%89%B2%E5%9B%9E%E6%96%87%E4%B8%B2.jpg) + +递归用来纵向遍历,for循环用来横向遍历,切割线(就是图中的红线)切割到字符串的结尾位置,说明找到了一个切割方法。 + +此时可以发现,切割问题的回溯搜索的过程和组合问题的回溯搜索的过程是差不多的。 + +## 回溯三部曲 + +* 递归函数参数 + +全局变量数组path存放切割后回文的子串,二维数组result存放结果集。 (这两个参数可以放到函数参数里) + +本题递归函数参数还需要startIndex,因为切割过的地方,不能重复切割,和组合问题也是保持一致的。 + +在[回溯算法:求组合总和(二)](https://mp.weixin.qq.com/s/FLg8G6EjVcxBjwCbzpACPw)中我们深入探讨了组合问题什么时候需要startIndex,什么时候不需要startIndex。 + +代码如下: + +```C++ +vector> result; +vector path; // 放已经回文的子串 +void backtracking (const string& s, int startIndex) { +``` + +* 递归函数终止条件 + +![131.分割回文串](https://code-thinking.cdn.bcebos.com/pics/131.%E5%88%86%E5%89%B2%E5%9B%9E%E6%96%87%E4%B8%B2.jpg) + +从树形结构的图中可以看出:切割线切到了字符串最后面,说明找到了一种切割方法,此时就是本层递归的终止终止条件。 + +**那么在代码里什么是切割线呢?** + +在处理组合问题的时候,递归参数需要传入startIndex,表示下一轮递归遍历的起始位置,这个startIndex就是切割线。 + +所以终止条件代码如下: + +```C++ +void backtracking (const string& s, int startIndex) { + // 如果起始位置已经大于s的大小,说明已经找到了一组分割方案了 + if (startIndex >= s.size()) { + result.push_back(path); + return; + } +} +``` + +* 单层搜索的逻辑 + +**来看看在递归循环,中如何截取子串呢?** + +在`for (int i = startIndex; i < s.size(); i++)`循环中,我们 定义了起始位置startIndex,那么 [startIndex, i] 就是要截取的子串。 + +首先判断这个子串是不是回文,如果是回文,就加入在`vector path`中,path用来记录切割过的回文子串。 + +代码如下: + +```C++ +for (int i = startIndex; i < s.size(); i++) { + if (isPalindrome(s, startIndex, i)) { // 是回文子串 + // 获取[startIndex,i]在s中的子串 + string str = s.substr(startIndex, i - startIndex + 1); + path.push_back(str); + } else { // 如果不是则直接跳过 + continue; + } + backtracking(s, i + 1); // 寻找i+1为起始位置的子串 + path.pop_back(); // 回溯过程,弹出本次已经填在的子串 +} +``` + +**注意切割过的位置,不能重复切割,所以,backtracking(s, i + 1); 传入下一层的起始位置为i + 1**。 + +## 判断回文子串 + +最后我们看一下回文子串要如何判断了,判断一个字符串是否是回文。 + +可以使用双指针法,一个指针从前向后,一个指针从后先前,如果前后指针所指向的元素是相等的,就是回文字符串了。 + +那么判断回文的C++代码如下: + +```C++ + bool isPalindrome(const string& s, int start, int end) { + for (int i = start, j = end; i < j; i++, j--) { + if (s[i] != s[j]) { + return false; + } + } + return true; + } +``` + +如果大家对双指针法有生疏了,传送门:[双指针法:总结篇!](https://mp.weixin.qq.com/s/_p7grwjISfMh0U65uOyCjA) + +此时关键代码已经讲解完毕,整体代码如下(详细注释了) + +## C++整体代码 + +根据Carl给出的回溯算法模板: + +```C++ +void backtracking(参数) { + if (终止条件) { + 存放结果; + return; + } + + for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) { + 处理节点; + backtracking(路径,选择列表); // 递归 + 回溯,撤销处理结果 + } +} + +``` + +不难写出如下代码: + +```C++ +class Solution { +private: + vector> result; + vector path; // 放已经回文的子串 + void backtracking (const string& s, int startIndex) { + // 如果起始位置已经大于s的大小,说明已经找到了一组分割方案了 + if (startIndex >= s.size()) { + result.push_back(path); + return; + } + for (int i = startIndex; i < s.size(); i++) { + if (isPalindrome(s, startIndex, i)) { // 是回文子串 + // 获取[startIndex,i]在s中的子串 + string str = s.substr(startIndex, i - startIndex + 1); + path.push_back(str); + } else { // 不是回文,跳过 + continue; + } + backtracking(s, i + 1); // 寻找i+1为起始位置的子串 + path.pop_back(); // 回溯过程,弹出本次已经填在的子串 + } + } + bool isPalindrome(const string& s, int start, int end) { + for (int i = start, j = end; i < j; i++, j--) { + if (s[i] != s[j]) { + return false; + } + } + return true; + } +public: + vector> partition(string s) { + result.clear(); + path.clear(); + backtracking(s, 0); + return result; + } +}; +``` + +## 总结 + +这道题目在leetcode上是中等,但可以说是hard的题目了,但是代码其实就是按照模板的样子来的。 + +那么难究竟难在什么地方呢? + +**我列出如下几个难点:** + +* 切割问题可以抽象为组合问题 +* 如何模拟那些切割线 +* 切割问题中递归如何终止 +* 在递归循环中如何截取子串 +* 如何判断回文 + +**我们平时在做难题的时候,总结出来难究竟难在哪里也是一种需要锻炼的能力**。 + +一些同学可能遇到题目比较难,但是不知道题目难在哪里,反正就是很难。其实这样还是思维不够清晰,这种总结的能力需要多接触多锻炼。 + +**本题我相信很多同学主要卡在了第一个难点上:就是不知道如何切割,甚至知道要用回溯法,也不知道如何用。也就是没有体会到按照求组合问题的套路就可以解决切割**。 + +如果意识到这一点,算是重大突破了。接下来就可以对着模板照葫芦画瓢。 + +**但接下来如何模拟切割线,如何终止,如何截取子串,其实都不好想,最后判断回文算是最简单的了**。 + +关于模拟切割线,其实就是index是上一层已经确定了的分割线,i是这一层试图寻找的新分割线 + +除了这些难点,**本题还有细节,例如:切割过的地方不能重复切割所以递归函数需要传入i + 1**。 + +所以本题应该是一个道hard题目了。 + +**可能刷过这道题目的录友都没感受到自己原来克服了这么多难点,就把这道题目AC了**,这应该叫做无招胜有招,人码合一,哈哈哈。 + +------------------------ + +* 微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) +* B站:[代码随想录](https://space.bilibili.com/525438321) +* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) + +![](../pics/公众号.png) + + diff --git a/problems/0216.组合总和III.md b/problems/0216.组合总和III.md index ca5b1bc1..d4d02b59 100644 --- a/problems/0216.组合总和III.md +++ b/problems/0216.组合总和III.md @@ -225,5 +225,6 @@ public: * B站:[代码随想录](https://space.bilibili.com/525438321) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) -![](https://img-blog.csdnimg.cn/20210416110157800.png) + +![](../pics/公众号.png) diff --git a/problems/0704.二分查找.md b/problems/0704.二分查找.md index 2293e165..9c82f6ba 100644 --- a/problems/0704.二分查找.md +++ b/problems/0704.二分查找.md @@ -146,5 +146,5 @@ public: * B站:[代码随想录](https://space.bilibili.com/525438321) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) -![](https://img-blog.csdnimg.cn/20210416110157800.png) +![](../pics/公众号.png) diff --git a/problems/什么是核心代码模式,什么又是ACM模式?.md b/problems/什么是核心代码模式,什么又是ACM模式?.md new file mode 100644 index 00000000..b282905f --- /dev/null +++ b/problems/什么是核心代码模式,什么又是ACM模式?.md @@ -0,0 +1,124 @@ + +

+ + + + +

+ +-------------------------- +现在很多企业都在牛客上进行面试,**很多录友和我反馈说搞不懂牛客上输入代码的ACM模式**。 + +什么是ACM输入模式呢? 就是自己构造输入数据格式,把要需要处理的容器填充好,OJ不会给你任何代码,包括include哪些函数都要自己写,最后也要自己控制返回数据的格式。 + +而力扣上是核心代码模式,就是把要处理的数据都已经放入容器里,可以直接写逻辑,例如这样: + +```C++ +class Solution { +public: + int minimumTotal(vector>& triangle) { + + } +}; +``` + +**如果大家从一开始学习算法就一直在力扣上的话,突然切到牛客网上的ACM模式会很不适应**。 + +因为我上学的时候就搞ACM,在POJ(北大的在线判题系统)和ZOJ(浙大的在线判题系统)上刷过6、7百道题目了,对这种ACM模式就很熟悉。 + +接下来我给大家讲一下ACM模式应该如何写。 + +这里我拿牛客上 腾讯2020校园招聘-后台 的面试题目来举一个例子,本题我不讲解题思路,只是拿本题为例讲解ACM输入输出格式。 + +题目描述: + +由于业绩优秀,公司给小Q放了 n 天的假,身为工作狂的小Q打算在在假期中工作、锻炼或者休息。他有个奇怪的习惯:不会连续两天工作或锻炼。只有当公司营业时,小Q才能去工作,只有当健身房营业时,小Q才能去健身,小Q一天只能干一件事。给出假期中公司,健身房的营业情况,求小Q最少需要休息几天。 + +输入描述: +第一行一个整数 表示放假天数 +第二行 n 个数 每个数为0或1,第 i 个数表示公司在第 i 天是否营业 +第三行 n 个数 每个数为0或1,第 i 个数表示健身房在第 i 天是否营业 +(1为营业 0为不营业) + +输出描述: +一个整数,表示小Q休息的最少天数 + +示例一: +输入: +4 +1 1 0 0 +0 1 1 0 + +输出: +2 + + +这道题如果要是力扣上的核心代码模式,OJ应该直接给出如下代码: + +```C++ +class Solution { +public: + int getDays(vector& work, vector& gym) { + // 处理逻辑 + } +}; +``` + +以上代码中我们直接写核心逻辑就行了,work数组,gym数组都是填好的,直接拿来用就行,处理完之后 return 结果就完事了。 + +那么看看ACM模式我们要怎么写呢。 + +ACM模式要求写出来的代码是直接可以本地运行的,所以我们需要自己写include哪些库函数,构造输入用例,构造输出用例。 + +拿本题来说,为了让代码可以运行,需要include这些库函数: + +```C++ +#include +#include +using namespace std; +``` + + +然后开始写主函数,来处理输入用例了,示例一 是一个完整的测试用例,一般我们测了一个用例还要测第二个用例,所以用:while(cin>>n) 来输入数据。 + +这里输入的n就是天数,得到天数之后,就可以来构造work数组和gym数组了。 + +此时就已经完成了输入用例构建,然后就是处理逻辑了,最后返回结果。 + +完整代码如下: + +```C++ +#include +#include +using namespace std; +int main() { + int n; + while (cin >> n) { + vector gym(n); + vector work(n); + for (int i = 0; i < n; i++) cin >> work[i]; + for (int i = 0; i < n; i++) cin >> gym[i]; + int result = 0; + + // 处理逻辑 + + cout << result << endl; + } + return 0; +} +``` + +可以看出ACM模式要比核心代码模式多写不少代码,相对来说ACM模式更锻炼代码能力,而核心代码模式是把侧重点完全放在算法逻辑上。 + +**国内企业现在很多都用牛客来进行面试,所以这种ACM模式大家还有必要熟悉一下**,以免面试的时候因为输入输出搞不懂而错失offer。 + +如果大家有精力的话,也可以去POJ上去刷刷题,POJ是ACM选手首选OJ,输入模式也是ACM模式。 + + +------------------------ + +* 微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) +* B站:[代码随想录](https://space.bilibili.com/525438321) +* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) + +![](../pics/公众号.png) diff --git a/problems/力扣上的代码想在本地编译运行?.md b/problems/力扣上的代码想在本地编译运行?.md new file mode 100644 index 00000000..dcfa297d --- /dev/null +++ b/problems/力扣上的代码想在本地编译运行?.md @@ -0,0 +1,71 @@ + +

+ + + + +

+ +很多录友都问过我一个问题,就是力扣上的代码如何在本地编译运行? + +其实在代码随想录刷题群里也经常出现这个场景,就是录友发一段代码上来,问大家这个代码怎么有问题? 如果我看到了一般我的回复:都是把那几个变量或者数组打印一下看看对不对,就知道了。 + +然后录友就问了:如何打日志呢? + +其实在力扣上打日志也挺方便的,我一般调试就是直接在力扣上打日志,偶尔需要把代码粘到本例来运行添加日志debug一下。 + +在力扣上直接打日志,这个就不用讲,C++的话想打啥直接cout啥就可以了。 + +我来说一说力扣代码如何在本题运行。 + +毕竟我们天天用力扣刷题,也应该知道力扣上的代码如何在本地编译运行。 + +其实挺简单的,大家看一遍就会了。 + +我拿我们刚讲过的这道题[动态规划:使用最小花费爬楼梯](https://mp.weixin.qq.com/s/djZB9gkyLFAKcQcSvKDorA)来做示范。 + +力扣746. 使用最小花费爬楼梯,完整的可以在直接本地运行的C++代码如下: + +```C++ +#include +#include +using namespace std; + +class Solution { +public: + int minCostClimbingStairs(vector& cost) { + vector dp(cost.size()); + dp[0] = cost[0]; + dp[1] = cost[1]; + for (int i = 2; i < cost.size(); i++) { + dp[i] = min(dp[i - 1], dp[i - 2]) + cost[i]; + } + return min(dp[cost.size() - 1], dp[cost.size() - 2]); + } +}; + +int main() { + int a[] = {1, 100, 1, 1, 1, 100, 1, 1, 100, 1}; + vector cost(a, a + sizeof(a) / sizeof(int)); + Solution solution; + cout << solution.minCostClimbingStairs(cost) << endl; +} +``` + +大家可以拿去跑一跑,直接粘到编译器上就行了。 + +我用的是linux下gcc来编译的,估计粘到其他编译器也没问题。 + +代码中可以看出,其实就是定义个main函数,构造个输入用例,然后定义一个solution变量,调用minCostClimbingStairs函数就可以了。 + +此时大家就可以随意构造测试数据,然后想怎么打日志就怎么打日志,没有找不出的bug,哈哈。 + + + +------------------------ + +* 微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) +* B站:[代码随想录](https://space.bilibili.com/525438321) +* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) + +![](../pics/公众号.png) diff --git a/problems/回溯算法理论基础.md b/problems/回溯算法理论基础.md index 03c36213..b1c8d5ce 100644 --- a/problems/回溯算法理论基础.md +++ b/problems/回溯算法理论基础.md @@ -8,6 +8,8 @@

+> 可以配合我的B站视频:[带你学透回溯算法(理论篇)](https://www.bilibili.com/video/BV1cy4y167mM/) 一起学习! + # 什么是回溯法 回溯法也可以叫做回溯搜索法,它是一种搜索的方式。 diff --git a/problems/看了这么多代码,谈一谈代码风格!.md b/problems/看了这么多代码,谈一谈代码风格!.md new file mode 100644 index 00000000..ccd169ba --- /dev/null +++ b/problems/看了这么多代码,谈一谈代码风格!.md @@ -0,0 +1,143 @@ + + +

+ + + + +

+ +-------------------------- + +其实在交流群里经常能看到大家发出来的代码,可以看出很多录友对代码规范应该不甚了解,代码看起来并不舒服。 + +所以呢,我给大家讲一讲代码规范,我主要以C++代码为例。 + +需要强调一下,代码规范并不是仅仅是让代码看着舒服,这是一个很重要的习惯。 + +# 题外话 + +工作之后,**特别是在大厂,看谁的技术牛不牛逼,不用看谁写出多牛逼的代码,就代码风格扫一眼,立刻就能看出来是正规军还是野生程序员**。 + +很多人甚至不屑于了解代码规范,认为实现功能就行,这种观点其实在上个世纪是很普遍的,因为那时候一般写代码不需要合作,自己一个人撸整个项目,想怎么写就怎么写。 + +现在一些小公司,甚至大公司里的某些技术团队也不注重代码规范,赶进度撸出功能就完事,这种情况就要分两方面看: + +* 第一种情况:这个项目在业务上赚到钱了,每年年终好几十万,那项目前期还关心啥代码风格,赶进度把功能撸出来,赚钱就完事了,例如15年的王者荣耀。 + +* 第二种情况:这个项目没赚到钱,半死不活的,代码还没有设计也没有规范,这样对技术人员的伤害就非常大了。 + +**而不注重代码风格的团队,99.99%都是第二种情况**,如果你赶上了第一种情况,那就恭喜你了,本文下面的内容可以不用看了,哈哈。 + +# 代码规范 + +## 变量命名 + +这里我简单说一说规范问题。 + +**权威的C++规范以Google为主**,我给大家下载了一份中文版本,在公众号「代码随想录」后台回复:googlec++编程规范,就可以领取。 + +**具体的规范要以自己团队风格为主**,融入团队才是最重要的。 + +我先来说说变量的命名。 + +主流有如下三种变量规则: + +* 小驼峰、大驼峰命名法 +* 下划线命名法 +* 匈牙利命名法 + +小驼峰,第一个单词首字母小写,后面其他单词首字母大写。例如 `int myAge;` + +大驼峰法把第一个单词的首字母也大写了。例如:``int MyAge;`` + +通常来讲 java和go都使用驼峰,C++的函数和结构体命名也是用大驼峰,**大家可以看到题解中我的C++代码风格就是小驼峰,因为leetcode上给出的默认函数的命名就是小驼峰,所以我入乡随俗**。 + +下划线命名法是名称中的每一个逻辑断点都用一个下划线来标记,例如:`int my_age`,**下划线命名法是随着C语言的出现流行起来的,如果大家看过UNIX高级编程或者UNIX网络编程,就会发现大量使用这种命名方式**。 + +匈牙利命名法是:变量名 = 属性 + 类型 + 对象描述,例如:`int iMyAge`,这种命名是一个来此匈牙利的程序员在微软内部推广起来,然后推广给了全世界的Windows开发人员。 + +这种命名方式在没有IDE的时代,可以很好的提醒开发人员遍历的意义,例如看到iMyAge,就知道它是一个int型的变量,而不用找它的定义,缺点是一旦该变量的属性,那么整个项目里这个变量名字都要改动,所以带来代码维护困难。 + +**目前IDE已经很发达了,都不用标记变量属性了,IDE就会帮我们识别了,所以基本没人用匈牙利命名法了**,虽然我不用IDE,VIM大法好。 + +我做了一下总结如图: + +![编程风格](https://img-blog.csdnimg.cn/20201119173039835.png) + +## 水平留白(代码空格) + +经常看到有的同学的代码都堆在一起,看起来都费劲,或者是有的间隔有空格,有的没有空格,很不统一,有的同学甚至为了让代码精简,把所有空格都省略掉了。 + +大家如果注意我题解上的代码风格,我的空格都是有统一规范的。 + +**我所有题解的C++代码,都是严格按照Google C++编程规范来的,这样代码看起来就让人感觉清爽一些**。 + +我举一些例子: + +操作符左右一定有空格,例如 +``` +i = i + 1; +``` + +分隔符(`,` 和`;`)前一位没有空格,后一位保持空格,例如: + +``` +int i, j; +for (int fastIndex = 0; fastIndex < nums.size(); fastIndex++) +``` + +花括号和函数保持同一行,并有一个空格例如: + +``` +while (n) { + n--; +} +``` + +控制语句(while,if,for)前都有一个空格,例如: +``` +while (n) { + if (k > 0) return 9; + n--; +} +``` + +以下是我刚写的力扣283.移动零的代码,大家可以看一下整体风格,注意空格的细节! +```C++ +class Solution { +public: + void moveZeroes(vector& nums) { + int slowIndex = 0; + for (int fastIndex = 0; fastIndex < nums.size(); fastIndex++) { + if (nums[fastIndex] != 0) { + nums[slowIndex++] = nums[fastIndex]; + } + } + for (int i = slowIndex; i < nums.size(); i++) { + nums[i] = 0; + } + } +}; +``` + +当然我并不是说一定要按照Google的规范来,代码风格其实统一就行,没有严格的说谁对谁错。 + +# 总结 + +如果还是学生,使用C++的话,可以按照题解中我的代码风格来,还是比较标准的。 + +如果不是C++就自己选一种代码风格坚持下来, + +如果已经工作的录友,就要融入团队的代码风格了,团队怎么写,自己就怎么来,毕竟不是一个人在战斗。 + +就酱,以后我还会陆续分享,关于代码,求职,学习工作之类的内容。 + + +------------------------ + +* 微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) +* B站:[代码随想录](https://space.bilibili.com/525438321) +* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) + +![](../pics/公众号.png)