diff --git a/problems/0027.移除元素.md b/problems/0027.移除元素.md index fadd4d7e..e3b75719 100644 --- a/problems/0027.移除元素.md +++ b/problems/0027.移除元素.md @@ -144,15 +144,28 @@ class Solution { Python: -```python +```python3 class Solution: - def removeElement(self, nums: List[int], val: int) -> int: - i,n = 0,len(nums) - for j in range(n): - if nums[j] != val: - nums[i] = nums[j] - i += 1 - return i + """双指针法 + 时间复杂度:O(n) + 空间复杂度:O(1) + """ + + @classmethod + def removeElement(cls, nums: List[int], val: int) -> int: + fast = slow = 0 + + while fast < len(nums): + + if nums[fast] != val: + nums[slow] = nums[fast] + slow += 1 + + # 当 fast 指针遇到要删除的元素时停止赋值 + # slow 指针停止移动, fast 指针继续前进 + fast += 1 + + return slow ``` @@ -201,19 +214,17 @@ end ``` Rust: ```rust -pub fn remove_element(nums: &mut Vec, val: i32) -> &mut Vec { - let mut start: usize = 0; - while start < nums.len() { - if nums[start] == val { - nums.remove(start); +impl Solution { + pub fn remove_element(nums: &mut Vec, val: i32) -> i32 { + let mut slowIdx = 0; + for pos in (0..nums.len()) { + if nums[pos]!=val { + nums[slowIdx] = nums[pos]; + slowIdx += 1; + } } - start += 1; + return (slowIdx) as i32; } - nums -} -fn main() { - let mut nums = vec![5,1,3,5,2,3,4,1]; - println!("{:?}",remove_element(&mut nums, 5)); } ``` diff --git a/problems/0040.组合总和II.md b/problems/0040.组合总和II.md index 55b66b22..4aab1782 100644 --- a/problems/0040.组合总和II.md +++ b/problems/0040.组合总和II.md @@ -63,7 +63,7 @@ candidates 中的每个数字在每个组合中只能使用一次。 都知道组合问题可以抽象为树形结构,那么“使用过”在这个树形结构上是有两个维度的,一个维度是同一树枝上使用过,一个维度是同一树层上使用过。**没有理解这两个层面上的“使用过” 是造成大家没有彻底理解去重的根本原因。** -那么问题来了,我们是要同一树层上使用过,还是统一树枝上使用过呢? +那么问题来了,我们是要同一树层上使用过,还是同一树枝上使用过呢? 回看一下题目,元素在同一个组合内是可以重复的,怎么重复都没事,但两个组合不能相同。 diff --git a/problems/0051.N皇后.md b/problems/0051.N皇后.md index 5404b620..69802ecb 100644 --- a/problems/0051.N皇后.md +++ b/problems/0051.N皇后.md @@ -21,18 +21,27 @@ n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并 每一种解法包含一个明确的 n 皇后问题的棋子放置方案,该方案中 'Q' 和 '.' 分别代表了皇后和空位。 示例: + 输入: 4 -输出: [ - [".Q..", // 解法 1 + +输出: + +解法 1 + +[ + [".Q..", "...Q", "Q...", "..Q."], - ["..Q.", // 解法 2 +解法 2 + + ["..Q.", "Q...", "...Q", ".Q.."] ] + 解释: 4 皇后问题存在两个不同的解法。 提示: @@ -332,7 +341,7 @@ class Solution { public boolean isValid(int row, int col, int n, char[][] chessboard) { // 检查列 - for (int i=0; i [[Int]] { } ``` +Rust: + +```rust +impl Solution { + pub fn generate_matrix(n: i32) -> Vec> { + let mut res = vec![vec![0; n as usize]; n as usize]; + let (mut startX, mut startY, mut offset): (usize, usize, usize) = (0, 0, 1); + let mut loopIdx = n/2; + let mid: usize = loopIdx as usize; + let mut count = 1; + let (mut i, mut j): (usize, usize) = (0, 0); + while loopIdx > 0 { + i = startX; + j = startY; + + while j < (startY + (n as usize) - offset) { + res[i][j] = count; + count += 1; + j += 1; + } + + while i < (startX + (n as usize) - offset) { + res[i][j] = count; + count += 1; + i += 1; + } + + while j > startY { + res[i][j] = count; + count += 1; + j -= 1; + } + + while i > startX { + res[i][j] = count; + count += 1; + i -= 1; + } + + startX += 1; + startY += 1; + offset += 2; + loopIdx -= 1; + } + + if(n % 2 == 1) { + res[mid][mid] = count; + } + res + } +} +``` ----------------------- diff --git a/problems/0093.复原IP地址.md b/problems/0093.复原IP地址.md index 9407809b..9f2ea6e7 100644 --- a/problems/0093.复原IP地址.md +++ b/problems/0093.复原IP地址.md @@ -309,7 +309,35 @@ class Solution { ``` python版本: +```python +class Solution: + def restoreIpAddresses(self, s: str) -> List[str]: + res = [] + path = [] # 存放分割后的字符 + # 判断数组中的数字是否合法 + def isValid(p): + if p == '0': return True # 解决"0000" + if p[0] == '0': return False + if int(p) > 0 and int(p) <256: return True + return False + def backtrack(s, startIndex): + if len(s) > 12: return # 字符串长度最大为12 + if len(path) == 4 and startIndex == len(s): # 确保切割完,且切割后的长度为4 + res.append(".".join(path[:])) # 字符拼接 + return + + for i in range(startIndex, len(s)): + if len(s) - startIndex > 3*(4 - len(path)): continue # 剪枝,剩下的字符串大于允许的最大长度则跳过 + p = s[startIndex:i+1] # 分割字符 + if isValid(p): # 判断字符是否有效 + path.append(p) + else: continue + backtrack(s, i + 1) # 寻找i+1为起始位置的子串 + path.pop() + backtrack(s, 0) + return res +``` ```python class Solution(object): def restoreIpAddresses(self, s): diff --git a/problems/0102.二叉树的层序遍历.md b/problems/0102.二叉树的层序遍历.md index e62a3e66..a57a92aa 100644 --- a/problems/0102.二叉树的层序遍历.md +++ b/problems/0102.二叉树的层序遍历.md @@ -1528,6 +1528,29 @@ public: ``` Java: +```Java +class Solution { + public int maxDepth(TreeNode root) { + if (root == null) return 0; + Queue que = new LinkedList<>(); + que.offer(root); + int depth = 0; + while (!que.isEmpty()) + { + int len = que.size(); + while (len > 0) + { + TreeNode node = que.poll(); + if (node.left != null) que.offer(node.left); + if (node.right != null) que.offer(node.right); + len--; + } + depth++; + } + return depth; + } +} +``` Python: diff --git a/problems/0104.二叉树的最大深度.md b/problems/0104.二叉树的最大深度.md index d086686d..cde3d460 100644 --- a/problems/0104.二叉树的最大深度.md +++ b/problems/0104.二叉树的最大深度.md @@ -311,6 +311,35 @@ class solution { } ``` +### 559.n叉树的最大深度 +```java +class solution { + /** + * 迭代法,使用层序遍历 + */ + public int maxDepth(Node root) { + if (root == null) return 0; + int depth = 0; + Queue que = new LinkedList<>(); + que.offer(root); + while (!que.isEmpty()) + { + depth ++; + int len = que.size(); + while (len > 0) + { + Node node = que.poll(); + for (int i = 0; i < node.children.size(); i++) + if (node.children.get(i) != null) + que.offer(node.children.get(i)); + len--; + } + } + return depth; + } +} +``` + ## python ### 104.二叉树的最大深度 @@ -505,21 +534,51 @@ var maxdepth = function(root) { 二叉树最大深度层级遍历 ```javascript -var maxdepth = function(root) { - //使用递归的方法 递归三部曲 - //1. 确定递归函数的参数和返回值 - const getdepth=function(node){ - //2. 确定终止条件 - if(node===null){ - return 0; +var maxDepth = function(root) { + if(!root) return 0 + let count = 0 + const queue = [root] + while(queue.length) { + let size = queue.length + /* 层数+1 */ + count++ + while(size--) { + let node = queue.shift(); + node.left && queue.push(node.left); + node.right && queue.push(node.right); } - //3. 确定单层逻辑 - let leftdepth=getdepth(node.left); - let rightdepth=getdepth(node.right); - let depth=1+math.max(leftdepth,rightdepth); - return depth; } - return getDepth(root); + return count +}; +``` + +N叉树的最大深度 递归写法 +```js +var maxDepth = function(root) { + if(!root) return 0 + let depth = 0 + for(let node of root.children) { + depth = Math.max(depth, maxDepth(node)) + } + return depth + 1 +} +``` + +N叉树的最大深度 层序遍历 +```js +var maxDepth = function(root) { + if(!root) return 0 + let count = 0 + let queue = [root] + while(queue.length) { + let size = queue.length + count++ + while(size--) { + let node = queue.shift() + node && (queue = [...queue, ...node.children]) + } + } + return count }; ``` diff --git a/problems/0122.买卖股票的最佳时机II.md b/problems/0122.买卖股票的最佳时机II.md index ff1b6d4a..bd837eea 100644 --- a/problems/0122.买卖股票的最佳时机II.md +++ b/problems/0122.买卖股票的最佳时机II.md @@ -139,17 +139,11 @@ Java: // 贪心思路 class Solution { public int maxProfit(int[] prices) { - int sum = 0; - int profit = 0; - int buy = prices[0]; + int result = 0; for (int i = 1; i < prices.length; i++) { - profit = prices[i] - buy; - if (profit > 0) { - sum += profit; - } - buy = prices[i]; + result += Math.max(prices[i] - prices[i - 1], 0); } - return sum; + return result; } } ``` @@ -235,6 +229,21 @@ var maxProfit = function(prices) { }; ``` +C: +```c +int maxProfit(int* prices, int pricesSize){ + int result = 0; + int i; + //从第二个元素开始遍历数组,与之前的元素进行比较 + for(i = 1; i < pricesSize; ++i) { + //若该元素比前面元素大,则说明有利润。代表买入 + if(prices[i] > prices[i-1]) + result+= prices[i]-prices[i-1]; + } + return result; +} +``` + ----------------------- * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * B站视频:[代码随想录](https://space.bilibili.com/525438321) diff --git a/problems/0131.分割回文串.md b/problems/0131.分割回文串.md index 6125b6be..f2e108e8 100644 --- a/problems/0131.分割回文串.md +++ b/problems/0131.分割回文串.md @@ -292,7 +292,8 @@ class Solution { ``` Python: -```py +```python +# 版本一 class Solution: def partition(self, s: str) -> List[List[str]]: res = [] @@ -310,7 +311,36 @@ class Solution: return res ``` - +```python +# 版本二 +class Solution: + def partition(self, s: str) -> List[List[str]]: + res = [] + path = [] #放已经回文的子串 + # 双指针法判断是否是回文串 + def isPalindrome(s): + n = len(s) + i, j = 0, n - 1 + while i < j: + if s[i] != s[j]:return False + i += 1 + j -= 1 + return True + + def backtrack(s, startIndex): + if startIndex >= len(s): # 如果起始位置已经大于s的大小,说明已经找到了一组分割方案了 + res.append(path[:]) + return + for i in range(startIndex, len(s)): + p = s[startIndex:i+1] # 获取[startIndex,i+1]在s中的子串 + if isPalindrome(p): # 是回文子串 + path.append(p) + else: continue #不是回文,跳过 + backtrack(s, i + 1) + path.pop() #回溯过程,弹出本次已经填在path的子串 + backtrack(s, 0) + return res +``` Go: > 注意切片(go切片是披着值类型外衣的引用类型) diff --git a/problems/0150.逆波兰表达式求值.md b/problems/0150.逆波兰表达式求值.md index bcde7d5b..36652109 100644 --- a/problems/0150.逆波兰表达式求值.md +++ b/problems/0150.逆波兰表达式求值.md @@ -13,7 +13,7 @@ # 150. 逆波兰表达式求值 -https://leetcode-cn.com/problems/evaluate-reverse-polish-notation/ +[力扣题目链接](https://leetcode-cn.com/problems/evaluate-reverse-polish-notation/) 根据 逆波兰表示法,求表达式的值。 @@ -23,7 +23,7 @@ https://leetcode-cn.com/problems/evaluate-reverse-polish-notation/ 整数除法只保留整数部分。 给定逆波兰表达式总是有效的。换句话说,表达式总会得出有效数值且不存在除数为 0 的情况。 -  + 示例 1: * 输入: ["2", "1", "+", "3", " * "] @@ -37,16 +37,21 @@ https://leetcode-cn.com/problems/evaluate-reverse-polish-notation/ 示例 3: * 输入: ["10", "6", "9", "3", "+", "-11", " * ", "/", " * ", "17", "+", "5", "+"] + * 输出: 22 + * 解释:该算式转化为常见的中缀算术表达式为: + + ``` ((10 * (6 / ((9 + 3) * -11))) + 17) + 5 -= ((10 * (6 / (12 * -11))) + 17) + 5 -= ((10 * (6 / -132)) + 17) + 5 -= ((10 * 0) + 17) + 5 -= (0 + 17) + 5 -= 17 + 5 -= 22 -  + = ((10 * (6 / (12 * -11))) + 17) + 5 + = ((10 * (6 / -132)) + 17) + 5 + = ((10 * 0) + 17) + 5 + = (0 + 17) + 5 + = 17 + 5 + = 22 + ``` + 逆波兰表达式:是一种后缀表达式,所谓后缀就是指算符写在后面。 @@ -62,7 +67,7 @@ https://leetcode-cn.com/problems/evaluate-reverse-polish-notation/ # 思路 -在上一篇文章中[1047.删除字符串中的所有相邻重复项](https://mp.weixin.qq.com/s/1-x6r1wGA9mqIHW5LrMvBg)提到了 递归就是用栈来实现的。 +在上一篇文章中[1047.删除字符串中的所有相邻重复项](https://programmercarl.com/1047.删除字符串中的所有相邻重复项.html)提到了 递归就是用栈来实现的。 所以**栈与递归之间在某种程度上是可以转换的!** 这一点我们在后续讲解二叉树的时候,会更详细的讲解到。 @@ -70,12 +75,12 @@ https://leetcode-cn.com/problems/evaluate-reverse-polish-notation/ 但我们没有必要从二叉树的角度去解决这个问题,只要知道逆波兰表达式是用后续遍历的方式把二叉树序列化了,就可以了。 -在进一步看,本题中每一个子表达式要得出一个结果,然后拿这个结果再进行运算,那么**这岂不就是一个相邻字符串消除的过程,和[1047.删除字符串中的所有相邻重复项](https://mp.weixin.qq.com/s/1-x6r1wGA9mqIHW5LrMvBg)中的对对碰游戏是不是就非常像了。** +在进一步看,本题中每一个子表达式要得出一个结果,然后拿这个结果再进行运算,那么**这岂不就是一个相邻字符串消除的过程,和[1047.删除字符串中的所有相邻重复项](https://programmercarl.com/1047.删除字符串中的所有相邻重复项.html)中的对对碰游戏是不是就非常像了。** 如动画所示: ![150.逆波兰表达式求值](https://code-thinking.cdn.bcebos.com/gifs/150.逆波兰表达式求值.gif) -相信看完动画大家应该知道,这和[1047. 删除字符串中的所有相邻重复项](https://mp.weixin.qq.com/s/1-x6r1wGA9mqIHW5LrMvBg)是差不错的,只不过本题不要相邻元素做消除了,而是做运算! +相信看完动画大家应该知道,这和[1047. 删除字符串中的所有相邻重复项](https://programmercarl.com/1047.删除字符串中的所有相邻重复项.html)是差不错的,只不过本题不要相邻元素做消除了,而是做运算! C++代码如下: diff --git a/problems/0189.旋转数组.md b/problems/0189.旋转数组.md index ba6edd1f..70aec5fe 100644 --- a/problems/0189.旋转数组.md +++ b/problems/0189.旋转数组.md @@ -131,6 +131,22 @@ class Solution: ## JavaScript ```js +var rotate = function (nums, k) { + function reverse(nums, i, j) { + while (i < j) { + [nums[i],nums[j]] = [nums[j],nums[i]]; // 解构赋值 + i++; + j--; + } + } + let n = nums.length; + k %= n; + if (k) { + reverse(nums, 0, n - 1); + reverse(nums, 0, k - 1); + reverse(nums, k, n - 1); + } +}; ``` ----------------------- diff --git a/problems/0205.同构字符串.md b/problems/0205.同构字符串.md index 5b0dd82b..5d20aa4a 100644 --- a/problems/0205.同构字符串.md +++ b/problems/0205.同构字符串.md @@ -97,6 +97,23 @@ class Solution { ## Go ```go +func isIsomorphic(s string, t string) bool { + map1 := make(map[byte]byte) + map2 := make(map[byte]byte) + for i := range s { + if _, ok := map1[s[i]]; !ok { + map1[s[i]] = t[i] // map1保存 s[i] 到 t[j]的映射 + } + if _, ok := map2[t[i]]; !ok { + map2[t[i]] = s[i] // map2保存 t[i] 到 s[j]的映射 + } + // 无法映射,返回 false + if (map1[s[i]] != t[i]) || (map2[t[i]] != s[i]) { + return false + } + } + return true +} ``` ## JavaScript diff --git a/problems/0209.长度最小的子数组.md b/problems/0209.长度最小的子数组.md index 45d2a229..ceca8c87 100644 --- a/problems/0209.长度最小的子数组.md +++ b/problems/0209.长度最小的子数组.md @@ -237,6 +237,32 @@ func minSubArrayLen(_ target: Int, _ nums: [Int]) -> Int { } ``` +Rust: + +```rust +impl Solution { + pub fn min_sub_array_len(target: i32, nums: Vec) -> i32 { + let (mut result, mut subLength): (i32, i32) = (i32::MAX, 0); + let (mut sum, mut i) = (0, 0); + + for (pos, val) in nums.iter().enumerate() { + sum += val; + while sum >= target { + subLength = (pos - i + 1) as i32; + if result > subLength { + result = subLength; + } + sum -= nums[i]; + i += 1; + } + } + if result == i32::MAX { + return 0; + } + result + } +} +``` ----------------------- diff --git a/problems/0225.用队列实现栈.md b/problems/0225.用队列实现栈.md index ccf93f1f..afa563e3 100644 --- a/problems/0225.用队列实现栈.md +++ b/problems/0225.用队列实现栈.md @@ -12,7 +12,7 @@ # 225. 用队列实现栈 -https://leetcode-cn.com/problems/implement-stack-using-queues/ +[力扣题目链接](https://leetcode-cn.com/problems/implement-stack-using-queues/) 使用队列实现栈的下列操作: @@ -34,7 +34,7 @@ https://leetcode-cn.com/problems/implement-stack-using-queues/ 有的同学可能疑惑这种题目有什么实际工程意义,**其实很多算法题目主要是对知识点的考察和教学意义远大于其工程实践的意义,所以面试题也是这样!** -刚刚做过[栈与队列:我用栈来实现队列怎么样?](https://mp.weixin.qq.com/s/Cj6R0qu8rFA7Et9V_ZMjCA)的同学可能依然想着用一个输入队列,一个输出队列,就可以模拟栈的功能,仔细想一下还真不行! +刚刚做过[栈与队列:我用栈来实现队列怎么样?](https://programmercarl.com/0232.用栈实现队列.html)的同学可能依然想着用一个输入队列,一个输出队列,就可以模拟栈的功能,仔细想一下还真不行! **队列模拟栈,其实一个队列就够了**,那么我们先说一说两个队列来实现栈的思路。 diff --git a/problems/0232.用栈实现队列.md b/problems/0232.用栈实现队列.md index e8bb877e..a4a73603 100644 --- a/problems/0232.用栈实现队列.md +++ b/problems/0232.用栈实现队列.md @@ -11,7 +11,7 @@ # 232.用栈实现队列 -https://leetcode-cn.com/problems/implement-queue-using-stacks/ +[力扣题目链接](https://leetcode-cn.com/problems/implement-queue-using-stacks/) 使用栈实现队列的下列操作: diff --git a/problems/0242.有效的字母异位词.md b/problems/0242.有效的字母异位词.md index 15bf14ca..1b6b3109 100644 --- a/problems/0242.有效的字母异位词.md +++ b/problems/0242.有效的字母异位词.md @@ -198,6 +198,29 @@ var isAnagram = function(s, t) { }; ``` +Swift: +```Swift +func isAnagram(_ s: String, _ t: String) -> Bool { + if s.count != t.count { + return false + } + var record = Array(repeating: 0, count: 26) + let aUnicodeScalar = "a".unicodeScalars.first!.value + for c in s.unicodeScalars { + record[Int(c.value - aUnicodeScalar)] += 1 + } + for c in t.unicodeScalars { + record[Int(c.value - aUnicodeScalar)] -= 1 + } + for value in record { + if value != 0 { + return false + } + } + return true +} +``` + ## 相关题目 * 383.赎金信 diff --git a/problems/0279.完全平方数.md b/problems/0279.完全平方数.md index 3c0f0414..865669c2 100644 --- a/problems/0279.完全平方数.md +++ b/problems/0279.完全平方数.md @@ -9,7 +9,7 @@ ## 279.完全平方数 -题目地址:https://leetcode-cn.com/problems/perfect-squares/ +[力扣题目链接](https://leetcode-cn.com/problems/perfect-squares/) 给定正整数 n,找到若干个完全平方数(比如 1, 4, 9, 16, ...)使得它们的和等于 n。你需要让组成和的完全平方数的个数最少。 @@ -36,7 +36,7 @@ **我来把题目翻译一下:完全平方数就是物品(可以无限件使用),凑个正整数n就是背包,问凑满这个背包最少有多少物品?** -感受出来了没,这么浓厚的完全背包氛围,而且和昨天的题目[动态规划:322. 零钱兑换](https://mp.weixin.qq.com/s/dyk-xNilHzNtVdPPLObSeQ)就是一样一样的! +感受出来了没,这么浓厚的完全背包氛围,而且和昨天的题目[动态规划:322. 零钱兑换](https://programmercarl.com/0322.零钱兑换.html)就是一样一样的! 动规五部曲分析如下: @@ -70,7 +70,7 @@ dp[0]表示 和为0的完全平方数的最小数量,那么dp[0]一定是0。 如果求排列数就是外层for遍历背包,内层for循环遍历物品。 -在[动态规划:322. 零钱兑换](https://mp.weixin.qq.com/s/dyk-xNilHzNtVdPPLObSeQ)中我们就深入探讨了这个问题,本题也是一样的,是求最小数! +在[动态规划:322. 零钱兑换](https://programmercarl.com/0322.零钱兑换.html)中我们就深入探讨了这个问题,本题也是一样的,是求最小数! **所以本题外层for遍历背包,里层for遍历物品,还是外层for遍历物品,内层for遍历背包,都是可以的!** @@ -146,7 +146,7 @@ public: ## 总结 -如果大家认真做了昨天的题目[动态规划:322. 零钱兑换](https://mp.weixin.qq.com/s/dyk-xNilHzNtVdPPLObSeQ),今天这道就非常简单了,一样的套路一样的味道。 +如果大家认真做了昨天的题目[动态规划:322. 零钱兑换](https://programmercarl.com/0322.零钱兑换.html),今天这道就非常简单了,一样的套路一样的味道。 但如果没有按照「代码随想录」的题目顺序来做的话,做动态规划或者做背包问题,上来就做这道题,那还是挺难的! diff --git a/problems/0300.最长上升子序列.md b/problems/0300.最长上升子序列.md index 0ac6e784..f9145f4c 100644 --- a/problems/0300.最长上升子序列.md +++ b/problems/0300.最长上升子序列.md @@ -8,13 +8,13 @@ ## 300.最长递增子序列 -题目链接:https://leetcode-cn.com/problems/longest-increasing-subsequence/ +[力扣题目链接](https://leetcode-cn.com/problems/longest-increasing-subsequence/) 给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。 子序列是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。 -  + 示例 1: 输入:nums = [10,9,2,5,3,7,101,18] 输出:4 @@ -27,7 +27,7 @@ 示例 3: 输入:nums = [7,7,7,7,7,7,7] 输出:1 -  + 提示: * 1 <= nums.length <= 2500 diff --git a/problems/0344.反转字符串.md b/problems/0344.反转字符串.md index 8925d0e1..a5f18d58 100644 --- a/problems/0344.反转字符串.md +++ b/problems/0344.反转字符串.md @@ -12,7 +12,7 @@ # 344.反转字符串 -https://leetcode-cn.com/problems/reverse-string/ +[力扣题目链接](https://leetcode-cn.com/problems/reverse-string/) 编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 char[] 的形式给出。 @@ -55,7 +55,7 @@ https://leetcode-cn.com/problems/reverse-string/ 接下来再来讲一下如何解决反转字符串的问题。 -大家应该还记得,我们已经讲过了[206.反转链表](https://mp.weixin.qq.com/s/ckEvIVGcNLfrz6OLOMoT0A)。 +大家应该还记得,我们已经讲过了[206.反转链表](https://programmercarl.com/0206.翻转链表.html)。 在反转链表中,使用了双指针的方法。 @@ -63,7 +63,7 @@ https://leetcode-cn.com/problems/reverse-string/ 因为字符串也是一种数组,所以元素在内存中是连续分布,这就决定了反转链表和反转字符串方式上还是有所差异的。 -如果对数组和链表原理不清楚的同学,可以看这两篇,[关于链表,你该了解这些!](https://mp.weixin.qq.com/s/fDGMmLrW7ZHlzkzlf_dZkw),[必须掌握的数组理论知识](https://mp.weixin.qq.com/s/c2KABb-Qgg66HrGf8z-8Og)。 +如果对数组和链表原理不清楚的同学,可以看这两篇,[关于链表,你该了解这些!](https://programmercarl.com/链表理论基础.html),[必须掌握的数组理论知识](https://programmercarl.com/数组理论基础.html)。 对于字符串,我们定义两个指针(也可以说是索引下表),一个从字符串前面,一个从字符串后面,两个指针同时向中间移动,并交换元素。 diff --git a/problems/0349.两个数组的交集.md b/problems/0349.两个数组的交集.md index 62abf639..752eee51 100644 --- a/problems/0349.两个数组的交集.md +++ b/problems/0349.两个数组的交集.md @@ -14,7 +14,7 @@ ## 349. 两个数组的交集 -https://leetcode-cn.com/problems/intersection-of-two-arrays/ +[力扣题目链接](https://leetcode-cn.com/problems/intersection-of-two-arrays/) 题意:给定两个数组,编写一个函数来计算它们的交集。 @@ -32,7 +32,7 @@ https://leetcode-cn.com/problems/intersection-of-two-arrays/ 这道题用暴力的解法时间复杂度是O(n^2),那来看看使用哈希法进一步优化。 -那么用数组来做哈希表也是不错的选择,例如[242. 有效的字母异位词](https://mp.weixin.qq.com/s/ffS8jaVFNUWyfn_8T31IdA) +那么用数组来做哈希表也是不错的选择,例如[242. 有效的字母异位词](https://programmercarl.com/0242.有效的字母异位词.html) 但是要注意,**使用数组来做哈希的题目,是因为题目都限制了数值的大小。** @@ -192,6 +192,22 @@ var intersection = function(nums1, nums2) { }; ``` +Swift: +```swift +func intersection(_ nums1: [Int], _ nums2: [Int]) -> [Int] { + var set1 = Set() + var set2 = Set() + for num in nums1 { + set1.insert(num) + } + for num in nums2 { + if set1.contains(num) { + set2.insert(num) + } + } + return Array(set2) +} +``` ## 相关题目 diff --git a/problems/0454.四数相加II.md b/problems/0454.四数相加II.md index 7bb24e59..4e61dc2f 100644 --- a/problems/0454.四数相加II.md +++ b/problems/0454.四数相加II.md @@ -161,15 +161,9 @@ class Solution(object): # count=0 # for x3 in nums3: # for x4 in nums4: -# key = -x3-x4 -# value = hashmap.get(key) - - # dict的get方法会返回None(key不存在)或者key对应的value - # 所以如果value==0,就会继续执行or,count+0,否则就会直接加value - # 这样就不用去写if判断了 - -# count += value or 0 - +# key = 0 - x3 - x4 +# value = hashmap[key] # 若差值(key)不存在,则value被赋值0 +# count += value # return count ``` diff --git a/problems/0455.分发饼干.md b/problems/0455.分发饼干.md index b6fa4a98..1e1c4afe 100644 --- a/problems/0455.分发饼干.md +++ b/problems/0455.分发饼干.md @@ -117,6 +117,7 @@ public: Java: ```java class Solution { + // 思路1:优先考虑饼干,小饼干先喂饱小胃口 public int findContentChildren(int[] g, int[] s) { Arrays.sort(g); Arrays.sort(s); @@ -132,10 +133,30 @@ class Solution { } } ``` +```java +class Solution { + // 思路2:优先考虑胃口,先喂饱大胃口 + public int findContentChildren(int[] g, int[] s) { + Arrays.sort(g); + Arrays.sort(s); + int count = 0; + int start = s.length - 1; + // 遍历胃口 + for (int index = g.length - 1; index >= 0; index--) { + if(start >= 0 && g[index] <= s[start]) { + start--; + count++; + } + } + return count; + } +} +``` Python: ```python3 class Solution: + # 思路1:优先考虑胃饼干 def findContentChildren(self, g: List[int], s: List[int]) -> int: g.sort() s.sort() @@ -145,6 +166,20 @@ class Solution: res += 1 return res ``` +```python +class Solution: + # 思路2:优先考虑胃口 + def findContentChildren(self, g: List[int], s: List[int]) -> int: + g.sort() + s.sort() + start, count = len(s) - 1, 0 + for index in range(len(g) - 1, -1, -1): # 先喂饱大胃口 + if start >= 0 and g[index] <= s[start]: + start -= 1 + count += 1 + return count +``` + Go: ```golang //排序后,局部最优 diff --git a/problems/0491.递增子序列.md b/problems/0491.递增子序列.md index 8eeb434d..ea113f4b 100644 --- a/problems/0491.递增子序列.md +++ b/problems/0491.递增子序列.md @@ -184,7 +184,7 @@ public: 这份代码在leetcode上提交,要比版本一耗时要好的多。 -**所以正如在[哈希表:总结篇!(每逢总结必经典)](https://programmercarl.com/哈希表总结.html)中说的那样,数组,set,map都可以做哈希表,而且数组干的活,map和set都能干,但如何数值范围小的话能用数组尽量用数组**。 +**所以正如在[哈希表:总结篇!(每逢总结必经典)](https://programmercarl.com/哈希表总结.html)中说的那样,数组,set,map都可以做哈希表,而且数组干的活,map和set都能干,但如果数值范围小的话能用数组尽量用数组**。 diff --git a/problems/0541.反转字符串II.md b/problems/0541.反转字符串II.md index 02713c65..df2fade8 100644 --- a/problems/0541.反转字符串II.md +++ b/problems/0541.反转字符串II.md @@ -12,7 +12,7 @@ # 541. 反转字符串II -https://leetcode-cn.com/problems/reverse-string-ii/ +[力扣题目链接](https://leetcode-cn.com/problems/reverse-string-ii/) 给定一个字符串 s 和一个整数 k,你需要对从字符串开头算起的每隔 2k 个字符的前 k 个字符进行反转。 @@ -65,7 +65,7 @@ public: }; ``` -那么我们也可以实现自己的reverse函数,其实和题目[344. 反转字符串](https://mp.weixin.qq.com/s/_rNm66OJVl92gBDIbGpA3w)道理是一样的。 +那么我们也可以实现自己的reverse函数,其实和题目[344. 反转字符串](https://programmercarl.com/0344.反转字符串.html)道理是一样的。 下面我实现的reverse函数区间是左闭右闭区间,代码如下: @@ -152,7 +152,35 @@ class Solution { } } ``` +```java +// 解法3 +class Solution { + public String reverseStr(String s, int k) { + char[] ch = s.toCharArray(); + // 1. 每隔 2k 个字符的前 k 个字符进行反转 + for (int i = 0; i< ch.length; i += 2 * k) { + // 2. 剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符 + if (i + k <= ch.length) { + reverse(ch, i, i + k -1); + continue; + } + // 3. 剩余字符少于 k 个,则将剩余字符全部反转 + reverse(ch, i, ch.length - 1); + } + return new String(ch); + } + // 定义翻转函数 + public void reverse(char[] ch, int i, int j) { + for (; i < j; i++, j--) { + char temp = ch[i]; + ch[i] = ch[j]; + ch[j] = temp; + } + + } +} +``` Python: ```python class Solution: @@ -226,6 +254,28 @@ var reverseStr = function(s, k) { ``` +Swift: + +```swift +func reverseStr(_ s: String, _ k: Int) -> String { + var ch = Array(s) + + for i in stride(from: 0, to: ch.count, by: 2 * k) { + var left = i + var right = min(s.count - 1, left + k - 1) + + while left < right { + (ch[left], ch[right]) = (ch[right], ch[left]) + left += 1 + right -= 1 + } + } + return String(ch) +} +``` + + + ----------------------- diff --git a/problems/0649.Dota2参议院.md b/problems/0649.Dota2参议院.md index 9cec7401..e2900824 100644 --- a/problems/0649.Dota2参议院.md +++ b/problems/0649.Dota2参议院.md @@ -10,6 +10,9 @@ # 649. Dota2 参议院 +[力扣题目链接](https://leetcode-cn.com/problems/dota2-senate/) + + Dota2 的世界里有两个阵营:Radiant(天辉)和 Dire(夜魇) Dota2 参议院由来自两派的参议员组成。现在参议院希望对一个 Dota2 游戏里的改变作出决定。他们以一个基于轮为过程的投票进行。在每一轮中,每一位参议员都可以行使两项权利中的一项: @@ -115,16 +118,102 @@ public: ## Java ```java +class Solution { + public String predictPartyVictory(String senateStr) { + // R = true表示本轮循环结束后,字符串里依然有R。D同理 + Boolean R = true, D = true; + // 当flag大于0时,R在D前出现,R可以消灭D。当flag小于0时,D在R前出现,D可以消灭R + int flag = 0; + byte[] senate = senateStr.getBytes(); + while (R && D) { // 一旦R或者D为false,就结束循环,说明本轮结束后只剩下R或者D了 + R = false; + D = false; + for (int i = 0; i < senate.length; i++) { + if (senate[i] == 'R') { + if (flag < 0) senate[i] = 0; // 消灭R,R此时为false + else R = true; // 如果没被消灭,本轮循环结束有R + flag++; + } + if (senate[i] == 'D') { + if (flag > 0) senate[i] = 0; + else D = true; + flag--; + } + } + } + // 循环结束之后,R和D只能有一个为true + return R == true ? "Radiant" : "Dire"; + } +} ``` ## Python ```python +class Solution: + def predictPartyVictory(self, senate: str) -> str: + # R = true表示本轮循环结束后,字符串里依然有R。D同理 + R , D = True, True + + # 当flag大于0时,R在D前出现,R可以消灭D。当flag小于0时,D在R前出现,D可以消灭R + flag = 0 + + senate = list(senate) + while R and D: # 一旦R或者D为false,就结束循环,说明本轮结束后只剩下R或者D了 + R = False + D = False + for i in range(len(senate)) : + if senate[i] == 'R' : + if flag < 0: senate[i] = '0' # 消灭R,R此时为false + else: R = True # 如果没被消灭,本轮循环结束有R + flag += 1 + if senate[i] == 'D': + if flag > 0: senate[i] = '0' + else: D = True + flag -= 1 + # 循环结束之后,R和D只能有一个为true + return "Radiant" if R else "Dire" ``` ## Go ```go + +func predictPartyVictory(senateStr string) string { + // R = true表示本轮循环结束后,字符串里依然有R。D同理 + R, D := true, true + // 当flag大于0时,R在D前出现,R可以消灭D。当flag小于0时,D在R前出现,D可以消灭R + flag := 0 + + senate := []byte(senateStr) + for R && D { // 一旦R或者D为false,就结束循环,说明本轮结束后只剩下R或者D了 + R = false + D = false + for i := 0; i < len(senate); i++ { + if senate[i] == 'R' { + if flag < 0 { + senate[i] = 0 // 消灭R,R此时为false + } else { + R = true // 如果没被消灭,本轮循环结束有R + } + flag++; + } + if (senate[i] == 'D') { + if flag > 0 { + senate[i] = 0 + } else { + D = true + } + flag-- + } + } + } + // 循环结束之后,R和D只能有一个为true + if R { + return "Radiant" + } + return "Dire"; +} ``` ## JavaScript diff --git a/problems/0704.二分查找.md b/problems/0704.二分查找.md index e576443e..495f7367 100644 --- a/problems/0704.二分查找.md +++ b/problems/0704.二分查找.md @@ -374,7 +374,7 @@ func search(nums: [Int], target: Int) -> Int { } else if target > nums[middle] { // 当目标在区间右侧,就需要更新左边的边界值,新区间为[middle + 1, right] left = middle + 1 - } else { + } else { // 当目标就是在中间,则返回中间值的下标 return middle } @@ -406,7 +406,77 @@ func search(nums: [Int], target: Int) -> Int { ``` +**Rust:** +```rust +# (版本一)左闭右闭区间 + +impl Solution { + pub fn search(nums: Vec, target: i32) -> i32 { + let mut left:usize = 0; + let mut right:usize = nums.len() - 1; + while left as i32 <= right as i32{ + let mid = (left + right) / 2; + if nums[mid] < target { + left = mid + 1; + } else if nums[mid] > target { + right = mid - 1; + } else { + return mid as i32; + } + } + -1 + } +} + +# (版本二)左闭右开区间 + +impl Solution { + pub fn search(nums: Vec, target: i32) -> i32 { + let mut left:usize = 0; + let mut right:usize = nums.len(); + while left < right { + let mid = (left + right) / 2; + if nums[mid] < target { + left = mid + 1; + } else if nums[mid] > target { + right = mid; + } else { + return mid as i32; + } + } + -1 + } +} +``` + +**C:** +```c +int search(int* nums, int numsSize, int target){ + int left = 0; + int right = numsSize-1; + int middle = 0; + //若left小于等于right,说明区间中元素不为0 + while(left<=right) { + //更新查找下标middle的值 + middle = (left+right)/2; + //此时target可能会在[left,middle-1]区间中 + if(nums[middle] > target) { + right = middle-1; + } + //此时target可能会在[middle+1,right]区间中 + else if(nums[middle] < target) { + left = middle+1; + } + //当前下标元素等于target值时,返回middle + else if(nums[middle] == target){ + return middle; + } + } + //若未找到target元素,返回-1 + return -1; +} +``` ----------------------- * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) diff --git a/problems/0968.监控二叉树.md b/problems/0968.监控二叉树.md index c715279a..737e92a0 100644 --- a/problems/0968.监控二叉树.md +++ b/problems/0968.监控二叉树.md @@ -406,6 +406,45 @@ var minCameraCover = function(root) { }; ``` +C: +```c +/* +**函数后序遍历二叉树。判断一个结点状态时,根据其左右孩子结点的状态进行判断 +**状态:0为没有被摄像头覆盖到。1为此结点处应设置摄像头。2为此结点已被摄像头覆盖 +*/ +int traversal(struct TreeNode* node, int* ans) { + //递归结束条件:传入结点为NULL,假设此结点能被摄像头覆盖。这样方便与对叶子结点的判断,将叶子结点设为0 + if(!node) + return 2; + //后序遍历二叉树,记录左右孩子的状态。根据左右孩子状态更新结点自身状态 + int left = traversal(node->left, ans); + int right = traversal(node->right, ans); + + //若左右孩子都可以被摄像头覆盖,将父亲结点状态设为0 + if(left == 2 && right == 2) { + return 0; + } + //若左右孩子有一个结点状态为没有被覆盖(0),则将父亲结点状态设置为摄像头 + if(left == 0 || right == 0) { + (*ans)++; + return 1; + } + //若左右孩子有一个为摄像头,证明父亲结点可以被覆盖。将父亲结点状态变为2 + if(left == 1 || right == 1) + return 2; + //逻辑不会走到-1,语句不会执行 + return -1; +} + +int minCameraCover(struct TreeNode* root){ + int ans = 0; + + //在对整个二叉树遍历后。头结点可能未被覆盖,这时候如果函数返回值为0,证明头结点未被覆盖。说明头结点也需要添置摄像头,ans++ + if(traversal(root, &ans) == 0) + ans++; + return ans; +} +``` ----------------------- * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) diff --git a/problems/1002.查找常用字符.md b/problems/1002.查找常用字符.md index a789373b..f7d323aa 100644 --- a/problems/1002.查找常用字符.md +++ b/problems/1002.查找常用字符.md @@ -10,7 +10,7 @@ # 1002. 查找常用字符 -https://leetcode-cn.com/problems/find-common-characters/ +[力扣题目链接](https://leetcode-cn.com/problems/find-common-characters/) 给定仅有小写字母组成的字符串数组 A,返回列表中的每个字符串中都显示的全部字符(包括重复字符)组成的列表。例如,如果一个字符在每个字符串中出现 3 次,但不是 4 次,则需要在最终答案中包含该字符 3 次。 @@ -23,7 +23,7 @@ https://leetcode-cn.com/problems/find-common-characters/ 【示例二】 输入:["cool","lock","cook"] 输出:["c","o"] -  + # 思路 @@ -40,9 +40,9 @@ https://leetcode-cn.com/problems/find-common-characters/ 可以看出这是指数级别的时间复杂度,非常高,而且代码实现也不容易,因为要统计 重复的字符,还要适当的替换或者去重。 -那我们还是哈希法吧。如果对哈希法不了解,可以看这篇:[关于哈希表,你该了解这些!](https://mp.weixin.qq.com/s/RSUANESA_tkhKhYe3ZR8Jg)。 +那我们还是哈希法吧。如果对哈希法不了解,可以看这篇:[关于哈希表,你该了解这些!](https://programmercarl.com/哈希表理论基础.html)。 -如果对用数组来做哈希法不了解的话,可以看这篇:[把数组当做哈希表来用,很巧妙!](https://mp.weixin.qq.com/s/ffS8jaVFNUWyfn_8T31IdA)。 +如果对用数组来做哈希法不了解的话,可以看这篇:[把数组当做哈希表来用,很巧妙!](https://programmercarl.com/0242.有效的字母异位词.html)。 了解了哈希法,理解了数组在哈希法中的应用之后,可以来看解题思路了。 @@ -181,7 +181,7 @@ class Solution: # 统计除第一个字符串外字符的出现频率 for i in range(1, len(words)): hashOtherStr = [0] * 26 - for j in range(len(words[0])): + for j in range(len(words[i])): hashOtherStr[ord(words[i][j]) - ord('a')] += 1 # 更新hash,保证hash里统计26个字符在所有字符串里出现的最小次数 for k in range(26): diff --git a/problems/1047.删除字符串中的所有相邻重复项.md b/problems/1047.删除字符串中的所有相邻重复项.md index b60a8d1d..b88fd618 100644 --- a/problems/1047.删除字符串中的所有相邻重复项.md +++ b/problems/1047.删除字符串中的所有相邻重复项.md @@ -13,7 +13,7 @@ # 1047. 删除字符串中的所有相邻重复项 -https://leetcode-cn.com/problems/remove-all-adjacent-duplicates-in-string/ +[力扣题目链接](https://leetcode-cn.com/problems/remove-all-adjacent-duplicates-in-string/) 给出由小写字母组成的字符串 S,重复项删除操作会选择两个相邻且相同的字母,并删除它们。 @@ -26,7 +26,7 @@ https://leetcode-cn.com/problems/remove-all-adjacent-duplicates-in-string/ * 输入:"abbaca" * 输出:"ca" * 解释:例如,在 "abbaca" 中,我们可以删除 "bb" 由于两字母相邻且相同,这是此时唯一可以执行删除操作的重复项。之后我们得到字符串 "aaca",其中又只有 "aa" 可以执行重复项删除操作,所以最后的字符串为 "ca"。 -  + 提示: * 1 <= S.length <= 20000 diff --git a/problems/为了绝杀编辑距离,卡尔做了三步铺垫.md b/problems/为了绝杀编辑距离,卡尔做了三步铺垫.md index 4a0ef0d2..31a5e448 100644 --- a/problems/为了绝杀编辑距离,卡尔做了三步铺垫.md +++ b/problems/为了绝杀编辑距离,卡尔做了三步铺垫.md @@ -14,7 +14,7 @@ ## 判断子序列 -[动态规划:392.判断子序列](https://mp.weixin.qq.com/s/2pjT4B4fjfOx5iB6N6xyng) 给定字符串 s 和 t ,判断 s 是否为 t 的子序列。 +[动态规划:392.判断子序列](https://programmercarl.com/0392.判断子序列.html) 给定字符串 s 和 t ,判断 s 是否为 t 的子序列。 这道题目 其实是可以用双指针或者贪心的的,但是我在开篇的时候就说了这是编辑距离的入门题目,因为从题意中我们也可以发现,只需要计算删除的情况,不用考虑增加和替换的情况。 @@ -33,9 +33,9 @@ else dp[i][j] = dp[i][j - 1]; ## 不同的子序列 -[动态规划:115.不同的子序列](https://mp.weixin.qq.com/s/1SULY2XVSROtk_hsoVLu8A) 给定一个字符串 s 和一个字符串 t ,计算在 s 的子序列中 t 出现的个数。 +[动态规划:115.不同的子序列](https://programmercarl.com/0115.不同的子序列.html) 给定一个字符串 s 和一个字符串 t ,计算在 s 的子序列中 t 出现的个数。 -本题虽然也只有删除操作,不用考虑替换增加之类的,但相对于[动态规划:392.判断子序列](https://mp.weixin.qq.com/s/2pjT4B4fjfOx5iB6N6xyng)就有难度了,这道题目双指针法可就做不了。 +本题虽然也只有删除操作,不用考虑替换增加之类的,但相对于[动态规划:392.判断子序列](https://programmercarl.com/0392.判断子序列.html)就有难度了,这道题目双指针法可就做不了。 当s[i - 1] 与 t[j - 1]相等时,dp[i][j]可以有两部分组成。 @@ -68,9 +68,9 @@ if (s[i - 1] == t[j - 1]) { ## 两个字符串的删除操作 -[动态规划:583.两个字符串的删除操作](https://mp.weixin.qq.com/s/a8BerpqSf76DCqkPDJrpYg)给定两个单词 word1 和 word2,找到使得 word1 和 word2 相同所需的最小步数,每步可以删除任意一个字符串中的一个字符。 +[动态规划:583.两个字符串的删除操作](https://programmercarl.com/0583.两个字符串的删除操作.html)给定两个单词 word1 和 word2,找到使得 word1 和 word2 相同所需的最小步数,每步可以删除任意一个字符串中的一个字符。 -本题和[动态规划:115.不同的子序列](https://mp.weixin.qq.com/s/1SULY2XVSROtk_hsoVLu8A)相比,其实就是两个字符串可以都可以删除了,情况虽说复杂一些,但整体思路是不变的。 +本题和[动态规划:115.不同的子序列](https://programmercarl.com/0115.不同的子序列.html)相比,其实就是两个字符串可以都可以删除了,情况虽说复杂一些,但整体思路是不变的。 * 当word1[i - 1] 与 word2[j - 1]相同的时候 @@ -100,10 +100,10 @@ if (word1[i - 1] == word2[j - 1]) { ## 编辑距离 -[动态规划:72.编辑距离](https://mp.weixin.qq.com/s/8aG71XjSgZG6kZbiAdkJnQ) 给你两个单词 word1 和 word2,请你计算出将 word1 转换成 word2 所使用的最少操作数 。 +[动态规划:72.编辑距离](https://programmercarl.com/0072.编辑距离.html) 给你两个单词 word1 和 word2,请你计算出将 word1 转换成 word2 所使用的最少操作数 。 -编辑距离终于来了,**有了前面三道题目的铺垫,应该有思路了**,本题是两个字符串可以增删改,比 [动态规划:判断子序列](https://mp.weixin.qq.com/s/2pjT4B4fjfOx5iB6N6xyng),[动态规划:不同的子序列](https://mp.weixin.qq.com/s/1SULY2XVSROtk_hsoVLu8A),[动态规划:两个字符串的删除操作](https://mp.weixin.qq.com/s/a8BerpqSf76DCqkPDJrpYg)都要复杂的多。 +编辑距离终于来了,**有了前面三道题目的铺垫,应该有思路了**,本题是两个字符串可以增删改,比 [动态规划:判断子序列](https://programmercarl.com/0392.判断子序列.html),[动态规划:不同的子序列](https://programmercarl.com/0115.不同的子序列.html),[动态规划:两个字符串的删除操作](https://programmercarl.com/0583.两个字符串的删除操作.html)都要复杂的多。 在确定递推公式的时候,首先要考虑清楚编辑的几种操作,整理如下: @@ -161,7 +161,7 @@ else { ## 总结 -心思的录友应该会发现我用了三道题做铺垫,才最后引出了[动态规划:72.编辑距离](https://mp.weixin.qq.com/s/8aG71XjSgZG6kZbiAdkJnQ) ,Carl的良苦用心呀,你们体会到了嘛! +心思的录友应该会发现我用了三道题做铺垫,才最后引出了[动态规划:72.编辑距离](https://programmercarl.com/0072.编辑距离.html) ,Carl的良苦用心呀,你们体会到了嘛! ## 其他语言版本 diff --git a/problems/二叉树中递归带着回溯.md b/problems/二叉树中递归带着回溯.md index 0f768e0f..7b0ccad7 100644 --- a/problems/二叉树中递归带着回溯.md +++ b/problems/二叉树中递归带着回溯.md @@ -11,11 +11,11 @@ > 补充一波 -昨天的总结篇中[还在玩耍的你,该总结啦!(本周小结之二叉树)](https://mp.weixin.qq.com/s/QMBUTYnoaNfsVHlUADEzKg),有两处问题需要说明一波。 +昨天的总结篇中[还在玩耍的你,该总结啦!(本周小结之二叉树)](https://programmercarl.com/周总结/20201003二叉树周末总结.html),有两处问题需要说明一波。 ## 求相同的树 -[还在玩耍的你,该总结啦!(本周小结之二叉树)](https://mp.weixin.qq.com/s/QMBUTYnoaNfsVHlUADEzKg)中求100.相同的树的代码中,我笔误贴出了 求对称树的代码了,细心的同学应该都发现了。 +[还在玩耍的你,该总结啦!(本周小结之二叉树)](https://programmercarl.com/周总结/20201003二叉树周末总结.html)中求100.相同的树的代码中,我笔误贴出了 求对称树的代码了,细心的同学应该都发现了。 那么如下我再给出求100. 相同的树 的代码,如下: @@ -42,13 +42,13 @@ public: }; ``` -以上的代码相对于:[二叉树:我对称么?](https://mp.weixin.qq.com/s/Kgf0gjvlDlNDfKIH2b1Oxg) 仅仅修改了变量的名字(为了符合判断相同树的语境)和 遍历的顺序。 +以上的代码相对于:[二叉树:我对称么?](https://programmercarl.com/0101.对称二叉树.html) 仅仅修改了变量的名字(为了符合判断相同树的语境)和 遍历的顺序。 -大家应该会体会到:**认清[判断对称树](https://mp.weixin.qq.com/s/Kgf0gjvlDlNDfKIH2b1Oxg)本质之后, 对称树的代码 稍作修改 就可以直接用来AC 100.相同的树。** +大家应该会体会到:**认清[判断对称树](https://programmercarl.com/0101.对称二叉树.html)本质之后, 对称树的代码 稍作修改 就可以直接用来AC 100.相同的树。** ## 递归中隐藏着回溯 -在[二叉树:找我的所有路径?](https://mp.weixin.qq.com/s/Osw4LQD2xVUnCJ-9jrYxJA)中我强调了本题其实是用到了回溯的,并且给出了第一个版本的代码,把回溯的过程充分的提现了出来。 +在[二叉树:找我的所有路径?](https://programmercarl.com/0257.二叉树的所有路径.html)中我强调了本题其实是用到了回溯的,并且给出了第一个版本的代码,把回溯的过程充分的提现了出来。 如下的代码充分的体现出回溯:(257. 二叉树的所有路径) @@ -166,7 +166,7 @@ if (cur->right) { **大家应该可以感受出来,如果把 `path + "->"`作为函数参数就是可以的,因为并有没有改变path的数值,执行完递归函数之后,path依然是之前的数值(相当于回溯了)** -如果有点遗忘了,建议把这篇[二叉树:找我的所有路径?](https://mp.weixin.qq.com/s/Osw4LQD2xVUnCJ-9jrYxJA)在仔细看一下,然后再看这里的总结,相信会豁然开朗。 +如果有点遗忘了,建议把这篇[二叉树:找我的所有路径?](https://programmercarl.com/0257.二叉树的所有路径.html)在仔细看一下,然后再看这里的总结,相信会豁然开朗。 这里我尽量把逻辑的每一个细节都抠出来展现了,希望对大家有所帮助! diff --git a/problems/二叉树总结篇.md b/problems/二叉树总结篇.md index 43276ec9..ee046366 100644 --- a/problems/二叉树总结篇.md +++ b/problems/二叉树总结篇.md @@ -22,105 +22,106 @@ ## 二叉树的理论基础 -* [关于二叉树,你该了解这些!](https://mp.weixin.qq.com/s/_ymfWYvTNd2GvWvC5HOE4A):二叉树的种类、存储方式、遍历方式、定义方式 +* [关于二叉树,你该了解这些!](https://programmercarl.com/二叉树理论基础.html):二叉树的种类、存储方式、遍历方式、定义方式 ## 二叉树的遍历方式 * 深度优先遍历 - * [二叉树:前中后序递归法](https://mp.weixin.qq.com/s/PwVIfxDlT3kRgMASWAMGhA):递归三部曲初次亮相 - * [二叉树:前中后序迭代法(一)](https://mp.weixin.qq.com/s/c_zCrGHIVlBjUH_hJtghCg):通过栈模拟递归 - * [二叉树:前中后序迭代法(二)统一风格](https://mp.weixin.qq.com/s/WKg0Ty1_3SZkztpHubZPRg) + * [二叉树:前中后序递归法](https://programmercarl.com/二叉树的递归遍历.html):递归三部曲初次亮相 + * [二叉树:前中后序迭代法(一)](https://programmercarl.com/二叉树的迭代遍历.html):通过栈模拟递归 + * [二叉树:前中后序迭代法(二)统一风格](https://programmercarl.com/二叉树的统一迭代法.html) * 广度优先遍历 - * [二叉树的层序遍历](https://mp.weixin.qq.com/s/Gb3BjakIKGNpup2jYtTzog):通过队列模拟 + * [二叉树的层序遍历](https://programmercarl.com/0102.二叉树的层序遍历.html):通过队列模拟 ## 求二叉树的属性 -* [二叉树:是否对称](https://mp.weixin.qq.com/s/Kgf0gjvlDlNDfKIH2b1Oxg) +* [二叉树:是否对称](https://programmercarl.com/0101.对称二叉树.html) * 递归:后序,比较的是根节点的左子树与右子树是不是相互翻转 * 迭代:使用队列/栈将两个节点顺序放入容器中进行比较 -* [二叉树:求最大深度](https://mp.weixin.qq.com/s/guKwV-gSNbA1CcbvkMtHBg) +* [二叉树:求最大深度](https://programmercarl.com/0104.二叉树的最大深度.html) * 递归:后序,求根节点最大高度就是最大深度,通过递归函数的返回值做计算树的高度 * 迭代:层序遍历 -* [二叉树:求最小深度](https://mp.weixin.qq.com/s/BH8-gPC3_QlqICDg7rGSGA) +* [二叉树:求最小深度](https://programmercarl.com/0111.二叉树的最小深度.html) * 递归:后序,求根节点最小高度就是最小深度,注意最小深度的定义 * 迭代:层序遍历 -* [二叉树:求有多少个节点](https://mp.weixin.qq.com/s/2_eAjzw-D0va9y4RJgSmXw) +* [二叉树:求有多少个节点](https://programmercarl.com/0222.完全二叉树的节点个数.html) * 递归:后序,通过递归函数的返回值计算节点数量 * 迭代:层序遍历 -* [二叉树:是否平衡](https://mp.weixin.qq.com/s/isUS-0HDYknmC0Rr4R8mww) +* [二叉树:是否平衡](https://programmercarl.com/0110.平衡二叉树.html) * 递归:后序,注意后序求高度和前序求深度,递归过程判断高度差 * 迭代:效率很低,不推荐 -* [二叉树:找所有路径](https://mp.weixin.qq.com/s/Osw4LQD2xVUnCJ-9jrYxJA) +* [二叉树:找所有路径](https://programmercarl.com/0257.二叉树的所有路径.html) * 递归:前序,方便让父节点指向子节点,涉及回溯处理根节点到叶子的所有路径 * 迭代:一个栈模拟递归,一个栈来存放对应的遍历路径 -* [二叉树:递归中如何隐藏着回溯](https://mp.weixin.qq.com/s/ivLkHzWdhjQQD1rQWe6zWA) - * 详解[二叉树:找所有路径](https://mp.weixin.qq.com/s/Osw4LQD2xVUnCJ-9jrYxJA)中递归如何隐藏着回溯 -* [二叉树:求左叶子之和](https://mp.weixin.qq.com/s/gBAgmmFielojU5Wx3wqFTA) +* [二叉树:递归中如何隐藏着回溯](https://programmercarl.com/二叉树中递归带着回溯.html) + * 详解[二叉树:找所有路径](https://programmercarl.com/0257.二叉树的所有路径.html)中递归如何隐藏着回溯 +* [二叉树:求左叶子之和](https://programmercarl.com/0404.左叶子之和.html) * 递归:后序,必须三层约束条件,才能判断是否是左叶子。 * 迭代:直接模拟后序遍历 -* [二叉树:求左下角的值](https://mp.weixin.qq.com/s/MH2gbLvzQ91jHPKqiub0Nw) +* [二叉树:求左下角的值](https://programmercarl.com/0513.找树左下角的值.html) * 递归:顺序无所谓,优先左孩子搜索,同时找深度最大的叶子节点。 * 迭代:层序遍历找最后一行最左边 -* [二叉树:求路径总和](https://mp.weixin.qq.com/s/6TWAVjxQ34kVqROWgcRFOg) +* [二叉树:求路径总和](https://programmercarl.com/0112.路径总和.html) * 递归:顺序无所谓,递归函数返回值为bool类型是为了搜索一条边,没有返回值是搜索整棵树。 * 迭代:栈里元素不仅要记录节点指针,还要记录从头结点到该节点的路径数值总和 ## 二叉树的修改与构造 -* [翻转二叉树](https://mp.weixin.qq.com/s/6gY1MiXrnm-khAAJiIb5Bg) +* [翻转二叉树](https://programmercarl.com/0226.翻转二叉树.html) * 递归:前序,交换左右孩子 * 迭代:直接模拟前序遍历 -* [构造二叉树](https://mp.weixin.qq.com/s/7r66ap2s-shvVvlZxo59xg) +* [构造二叉树](https://programmercarl.com/0106.从中序与后序遍历序列构造二叉树.html) * 递归:前序,重点在于找分割点,分左右区间构造 * 迭代:比较复杂,意义不大 -* [构造最大的二叉树](https://mp.weixin.qq.com/s/1iWJV6Aov23A7xCF4nV88w) +* [构造最大的二叉树](https://programmercarl.com/0654.最大二叉树.html) * 递归:前序,分割点为数组最大值,分左右区间构造 * 迭代:比较复杂,意义不大 -* [合并两个二叉树](https://mp.weixin.qq.com/s/3f5fbjOFaOX_4MXzZ97LsQ) +* [合并两个二叉树](https://programmercarl.com/0617.合并二叉树.html) * 递归:前序,同时操作两个树的节点,注意合并的规则 * 迭代:使用队列,类似层序遍历 ## 求二叉搜索树的属性 -* [二叉搜索树中的搜索](https://mp.weixin.qq.com/s/vsKrWRlETxCVsiRr8v_hHg) +* [二叉搜索树中的搜索](https://programmercarl.com/0700.二叉搜索树中的搜索.html) * 递归:二叉搜索树的递归是有方向的 * 迭代:因为有方向,所以迭代法很简单 -* [是不是二叉搜索树](https://mp.weixin.qq.com/s/8odY9iUX5eSi0eRFSXFD4Q) +* [是不是二叉搜索树](https://programmercarl.com/0098.验证二叉搜索树.html) * 递归:中序,相当于变成了判断一个序列是不是递增的 * 迭代:模拟中序,逻辑相同 -* [求二叉搜索树的最小绝对差](https://mp.weixin.qq.com/s/Hwzml6698uP3qQCC1ctUQQ) +* [求二叉搜索树的最小绝对差](https://programmercarl.com/0530.二叉搜索树的最小绝对差.html) * 递归:中序,双指针操作 * 迭代:模拟中序,逻辑相同 -* [求二叉搜索树的众数](https://mp.weixin.qq.com/s/KSAr6OVQIMC-uZ8MEAnGHg) +* [求二叉搜索树的众数](https://programmercarl.com/0501.二叉搜索树中的众数.html) + * 递归:中序,清空结果集的技巧,遍历一遍便可求众数集合 - * 迭代:模拟中序,逻辑相同 -* [二叉搜索树转成累加树](https://mp.weixin.qq.com/s/hZtJh4T5lIGBarY-lZJf6Q) + * [二叉搜索树转成累加树](https://programmercarl.com/0538.把二叉搜索树转换为累加树.html) + * 递归:中序,双指针操作累加 * 迭代:模拟中序,逻辑相同 ## 二叉树公共祖先问题 -* [二叉树的公共祖先问题](https://mp.weixin.qq.com/s/n6Rk3nc_X3TSkhXHrVmBTQ) +* [二叉树的公共祖先问题](https://programmercarl.com/0236.二叉树的最近公共祖先.html) * 递归:后序,回溯,找到左子树出现目标值,右子树节点目标值的节点。 * 迭代:不适合模拟回溯 -* [二叉搜索树的公共祖先问题](https://mp.weixin.qq.com/s/Ja9dVw2QhBcg_vV-1fkiCg) +* [二叉搜索树的公共祖先问题](https://programmercarl.com/0235.二叉搜索树的最近公共祖先.html) * 递归:顺序无所谓,如果节点的数值在目标区间就是最近公共祖先 * 迭代:按序遍历 ## 二叉搜索树的修改与构造 -* [二叉搜索树中的插入操作](https://mp.weixin.qq.com/s/lwKkLQcfbCNX2W-5SOeZEA) +* [二叉搜索树中的插入操作](https://programmercarl.com/0701.二叉搜索树中的插入操作.html) * 递归:顺序无所谓,通过递归函数返回值添加节点 * 迭代:按序遍历,需要记录插入父节点,这样才能做插入操作 -* [二叉搜索树中的删除操作](https://mp.weixin.qq.com/s/-p-Txvch1FFk3ygKLjPAKw) +* [二叉搜索树中的删除操作](https://programmercarl.com/0450.删除二叉搜索树中的节点.html) * 递归:前序,想清楚删除非叶子节点的情况 * 迭代:有序遍历,较复杂 -* [修剪二叉搜索树](https://mp.weixin.qq.com/s/QzmGfYUMUWGkbRj7-ozHoQ) +* [修剪二叉搜索树](https://programmercarl.com/0669.修剪二叉搜索树.html) * 递归:前序,通过递归函数返回值删除节点 * 迭代:有序遍历,较复杂 -* [构造二叉搜索树](https://mp.weixin.qq.com/s/sy3ygnouaZVJs8lhFgl9mw) +* [构造二叉搜索树](https://programmercarl.com/0108.将有序数组转换为二叉搜索树.html) * 递归:前序,数组中间节点分割 * 迭代:较复杂,通过三个队列来模拟 @@ -130,10 +131,10 @@ **每周小结都会对大家的疑问做统一解答,并且对每周的内容进行拓展和补充,所以一定要看,将细碎知识点一网打尽!** -* [本周小结!(二叉树系列一)](https://mp.weixin.qq.com/s/JWmTeC7aKbBfGx4TY6uwuQ) -* [本周小结!(二叉树系列二)](https://mp.weixin.qq.com/s/QMBUTYnoaNfsVHlUADEzKg) -* [本周小结!(二叉树系列三)](https://mp.weixin.qq.com/s/JLLpx3a_8jurXcz6ovgxtg) -* [本周小结!(二叉树系列四)](https://mp.weixin.qq.com/s/CbdtOTP0N-HIP7DR203tSg) +* [本周小结!(二叉树系列一)](https://programmercarl.com/周总结/20200927二叉树周末总结.html) +* [本周小结!(二叉树系列二)](https://programmercarl.com/周总结/20201003二叉树周末总结.html) +* [本周小结!(二叉树系列三)](https://programmercarl.com/周总结/20201010二叉树周末总结.html) +* [本周小结!(二叉树系列四)](https://programmercarl.com/周总结/20201017二叉树周末总结.html) ## 最后总结 @@ -145,7 +146,7 @@ * 求二叉搜索树的属性,一定是中序了,要不白瞎了有序性了。 -注意在普通二叉树的属性中,我用的是一般为后序,例如单纯求深度就用前序, [二叉树:找所有路径](https://mp.weixin.qq.com/s/Osw4LQD2xVUnCJ-9jrYxJA)也用了前序,这是为了方便让父节点指向子节点。 +注意在普通二叉树的属性中,我用的是一般为后序,例如单纯求深度就用前序,[二叉树:找所有路径](https://programmercarl.com/0257.二叉树的所有路径.html)也用了前序,这是为了方便让父节点指向子节点。 所以求普通二叉树的属性还是要具体问题具体分析。 diff --git a/problems/二叉树理论基础.md b/problems/二叉树理论基础.md index edd1fed4..94a0d67f 100644 --- a/problems/二叉树理论基础.md +++ b/problems/二叉树理论基础.md @@ -215,7 +215,7 @@ class TreeNode: ``` Go: -``` +```go type TreeNode struct { Val int Left *TreeNode @@ -224,7 +224,7 @@ type TreeNode struct { ``` JavaScript: -``` +```javascript function TreeNode(val, left, right) { this.val = (val===undefined ? 0 : val) this.left = (left===undefined ? null : left) diff --git a/problems/二叉树的统一迭代法.md b/problems/二叉树的统一迭代法.md index d105f4b8..d8299e10 100644 --- a/problems/二叉树的统一迭代法.md +++ b/problems/二叉树的统一迭代法.md @@ -12,9 +12,9 @@ > 统一写法是一种什么感觉 -此时我们在[二叉树:一入递归深似海,从此offer是路人](https://mp.weixin.qq.com/s/Ww60X5mIKWdMQV4cN3ejOA)中用递归的方式,实现了二叉树前中后序的遍历。 +此时我们在[二叉树:一入递归深似海,从此offer是路人](https://programmercarl.com/二叉树的递归遍历.html)中用递归的方式,实现了二叉树前中后序的遍历。 -在[二叉树:听说递归能做的,栈也能做!](https://mp.weixin.qq.com/s/OH7aCVJ5-Gi32PkNCoZk4A)中用栈实现了二叉树前后中序的迭代遍历(非递归)。 +在[二叉树:听说递归能做的,栈也能做!](https://programmercarl.com/二叉树的迭代遍历.html)中用栈实现了二叉树前后中序的迭代遍历(非递归)。 之后我们发现**迭代法实现的先中后序,其实风格也不是那么统一,除了先序和后序,有关联,中序完全就是另一个风格了,一会用栈遍历,一会又用指针来遍历。** @@ -24,7 +24,7 @@ **重头戏来了,接下来介绍一下统一写法。** -我们以中序遍历为例,在[二叉树:听说递归能做的,栈也能做!](https://mp.weixin.qq.com/s/OH7aCVJ5-Gi32PkNCoZk4A)中提到说使用栈的话,**无法同时解决访问节点(遍历节点)和处理节点(将元素放进结果集)不一致的情况**。 +我们以中序遍历为例,在[二叉树:听说递归能做的,栈也能做!](https://programmercarl.com/二叉树的迭代遍历.html)中提到说使用栈的话,**无法同时解决访问节点(遍历节点)和处理节点(将元素放进结果集)不一致的情况**。 **那我们就将访问的节点放入栈中,把要处理的节点也放入栈中但是要做标记。** diff --git a/problems/二叉树的迭代遍历.md b/problems/二叉树的迭代遍历.md index faa580e0..a1d65070 100644 --- a/problems/二叉树的迭代遍历.md +++ b/problems/二叉树的迭代遍历.md @@ -19,7 +19,7 @@ 为什么可以用迭代法(非递归的方式)来实现二叉树的前后中序遍历呢? -我们在[栈与队列:匹配问题都是栈的强项](https://mp.weixin.qq.com/s/1-x6r1wGA9mqIHW5LrMvBg)中提到了,**递归的实现就是:每一次递归调用都会把函数的局部变量、参数值和返回地址等压入调用栈中**,然后递归返回的时候,从栈顶弹出上一次递归的各项参数,所以这就是递归为什么可以返回上一层位置的原因。 +我们在[栈与队列:匹配问题都是栈的强项](https://programmercarl.com/1047.删除字符串中的所有相邻重复项.html)中提到了,**递归的实现就是:每一次递归调用都会把函数的局部变量、参数值和返回地址等压入调用栈中**,然后递归返回的时候,从栈顶弹出上一次递归的各项参数,所以这就是递归为什么可以返回上一层位置的原因。 此时大家应该知道我们用栈也可以是实现二叉树的前后中序遍历了。 diff --git a/problems/前序/上海互联网公司总结.md b/problems/前序/上海互联网公司总结.md index 05cbe1b0..08c15895 100644 --- a/problems/前序/上海互联网公司总结.md +++ b/problems/前序/上海互联网公司总结.md @@ -112,7 +112,7 @@ ## 总结 -大家如果看了[北京有这些互联网公司,你都知道么?](https://mp.weixin.qq.com/s/BKrjK4myNB-FYbMqW9f3yw)和[深圳原来有这么多互联网公司,你都知道么?](https://mp.weixin.qq.com/s/3VJHF2zNohBwDBxARFIn-Q)就可以看出中国互联网氛围最浓的当然是北京,其次就是上海! +大家如果看了[北京有这些互联网公司,你都知道么?](https://programmercarl.com/前序/北京互联网公司总结.html)和[深圳原来有这么多互联网公司,你都知道么?](https://programmercarl.com/前序/深圳互联网公司总结.html)就可以看出中国互联网氛围最浓的当然是北京,其次就是上海! 很多人说深圳才是第二,上海没有产生BAT之类的企业。 diff --git a/problems/前序/关于空间复杂度,可能有几个疑问?.md b/problems/前序/关于空间复杂度,可能有几个疑问?.md index 5b2f73e2..510979c9 100644 --- a/problems/前序/关于空间复杂度,可能有几个疑问?.md +++ b/problems/前序/关于空间复杂度,可能有几个疑问?.md @@ -10,9 +10,9 @@ # 空间复杂度分析 -* [关于时间复杂度,你不知道的都在这里!](https://mp.weixin.qq.com/s/LWBfehW1gMuEnXtQjJo-sw) -* [O(n)的算法居然超时了,此时的n究竟是多大?](https://mp.weixin.qq.com/s/73ryNsuPFvBQkt6BbhNzLA) -* [通过一道面试题目,讲一讲递归算法的时间复杂度!](https://mp.weixin.qq.com/s/I6ZXFbw09NR31F5CJR_geQ) +* [关于时间复杂度,你不知道的都在这里!](https://programmercarl.com/前序/关于时间复杂度,你不知道的都在这里!.html) +* [O(n)的算法居然超时了,此时的n究竟是多大?](https://programmercarl.com/前序/On的算法居然超时了,此时的n究竟是多大?.html) +* [通过一道面试题目,讲一讲递归算法的时间复杂度!](https://programmercarl.com/前序/通过一道面试题目,讲一讲递归算法的时间复杂度!.html) 那么一直还没有讲空间复杂度,所以打算陆续来补上,内容不难,大家可以读一遍文章就有整体的了解了。 diff --git a/problems/前序/力扣上的代码想在本地编译运行?.md b/problems/前序/力扣上的代码想在本地编译运行?.md index a0fcbcd8..970af7ff 100644 --- a/problems/前序/力扣上的代码想在本地编译运行?.md +++ b/problems/前序/力扣上的代码想在本地编译运行?.md @@ -23,7 +23,7 @@ 其实挺简单的,大家看一遍就会了。 -我拿我们刚讲过的这道题[动态规划:使用最小花费爬楼梯](https://mp.weixin.qq.com/s/djZB9gkyLFAKcQcSvKDorA)来做示范。 +我拿我们刚讲过的这道题[动态规划:使用最小花费爬楼梯](https://programmercarl.com/0746.使用最小花费爬楼梯.html)来做示范。 力扣746. 使用最小花费爬楼梯,完整的可以在直接本地运行的C++代码如下: diff --git a/problems/前序/北京互联网公司总结.md b/problems/前序/北京互联网公司总结.md index c770759f..0e22dad6 100644 --- a/problems/前序/北京互联网公司总结.md +++ b/problems/前序/北京互联网公司总结.md @@ -105,7 +105,7 @@ 可能是我写总结写习惯了,什么文章都要有一个总结,哈哈,那么我就总结一下。 -北京的互联网氛围绝对是最好的(暂不讨论户口和房价问题),大家如果看了[深圳原来有这么多互联网公司,你都知道么?](https://mp.weixin.qq.com/s/3VJHF2zNohBwDBxARFIn-Q)这篇之后,**会发现北京互联网外企和二线互联网公司数量多的优势,在深圳的互联网公司断档比较严重,如果去不了为数不多的一线公司,可选择的余地就非常少了,而北京选择的余地就很多!** +北京的互联网氛围绝对是最好的(暂不讨论户口和房价问题),大家如果看了[深圳原来有这么多互联网公司,你都知道么?](https://programmercarl.com/前序/深圳互联网公司总结.html)这篇之后,**会发现北京互联网外企和二线互联网公司数量多的优势,在深圳的互联网公司断档比较严重,如果去不了为数不多的一线公司,可选择的余地就非常少了,而北京选择的余地就很多!** 相对来说,深圳的硬件企业更多一些,因为珠三角制造业配套比较完善。而大多数互联网公司其实就是媒体公司,当然要靠近政治文化中心,这也是有原因的。 diff --git a/problems/前序/广州互联网公司总结.md b/problems/前序/广州互联网公司总结.md index 3cc18c8e..ae41c899 100644 --- a/problems/前序/广州互联网公司总结.md +++ b/problems/前序/广州互联网公司总结.md @@ -51,7 +51,7 @@ ## 总结 -同在广东省,难免不了要和深圳对比,大家如果看了这篇:[深圳原来有这么多互联网公司,你都知道么?](https://mp.weixin.qq.com/s/3VJHF2zNohBwDBxARFIn-Q)就能感受到鲜明的对比了。 +同在广东省,难免不了要和深圳对比,大家如果看了这篇:[深圳原来有这么多互联网公司,你都知道么?](https://programmercarl.com/前序/深圳互联网公司总结.html)就能感受到鲜明的对比了。 广州大厂高端岗位其实比较少,本土只有微信和网易,微信呢毕竟还是腾讯的分部,而网易被很多人认为是杭州企业,其实网易总部在广州。 diff --git a/problems/前序/杭州互联网公司总结.md b/problems/前序/杭州互联网公司总结.md index aebf5779..326a176b 100644 --- a/problems/前序/杭州互联网公司总结.md +++ b/problems/前序/杭州互联网公司总结.md @@ -67,11 +67,10 @@ * 大搜车(总部)中国领先的汽车交易服务供应商 * 二更(总部)自媒体 * 丁香园(总部) - ## 总结 -杭州距离上海非常近,难免不了和上海做对比,上海是金融之都,如果看了[上海有这些互联网公司,你都知道么?](https://mp.weixin.qq.com/s/iW4_rXQzc0fJDuSmPTUVdQ)就会发现上海互联网也是仅次于北京的。 +杭州距离上海非常近,难免不了和上海做对比,上海是金融之都,如果看了[上海有这些互联网公司,你都知道么?](https://programmercarl.com/前序/上海互联网公司总结.html)就会发现上海互联网也是仅次于北京的。 而杭州是阿里的大本营,到处都有阿里的影子,虽然有网易在,但是也基本是盖过去了,很多中小公司也都是阿里某某高管出来创业的。 diff --git a/problems/前序/递归算法的时间与空间复杂度分析.md b/problems/前序/递归算法的时间与空间复杂度分析.md index b6c79f25..27b9d7cc 100644 --- a/problems/前序/递归算法的时间与空间复杂度分析.md +++ b/problems/前序/递归算法的时间与空间复杂度分析.md @@ -9,7 +9,7 @@ # 递归算法的时间与空间复杂度分析! -之前在[通过一道面试题目,讲一讲递归算法的时间复杂度!](https://mp.weixin.qq.com/s/I6ZXFbw09NR31F5CJR_geQ)中详细讲解了递归算法的时间复杂度,但没有讲空间复杂度。 +之前在[通过一道面试题目,讲一讲递归算法的时间复杂度!](https://programmercarl.com/前序/通过一道面试题目,讲一讲递归算法的时间复杂度!.html)中详细讲解了递归算法的时间复杂度,但没有讲空间复杂度。 本篇讲通过求斐波那契数列和二分法再来深入分析一波递归算法的时间和空间复杂度,细心看完,会刷新对递归的认知! diff --git a/problems/剑指Offer05.替换空格.md b/problems/剑指Offer05.替换空格.md index 3f373d0d..47907319 100644 --- a/problems/剑指Offer05.替换空格.md +++ b/problems/剑指Offer05.替换空格.md @@ -9,7 +9,7 @@ # 题目:剑指Offer 05.替换空格 -https://leetcode-cn.com/problems/ti-huan-kong-ge-lcof/ +[力扣题目链接](https://leetcode-cn.com/problems/ti-huan-kong-ge-lcof/) 请实现一个函数,把字符串 s 中的每个空格替换成"%20"。 @@ -81,12 +81,12 @@ public: 此时算上本题,我们已经做了七道双指针相关的题目了分别是: -* [27.移除元素](https://mp.weixin.qq.com/s/RMkulE4NIb6XsSX83ra-Ww) -* [15.三数之和](https://mp.weixin.qq.com/s/QfTNEByq1YlNSXRKEumwHg) -* [18.四数之和](https://mp.weixin.qq.com/s/SBU3THi1Kv6Sar7htqCB2Q) -* [206.翻转链表](https://mp.weixin.qq.com/s/ckEvIVGcNLfrz6OLOMoT0A) -* [142.环形链表II](https://mp.weixin.qq.com/s/gt_VH3hQTqNxyWcl1ECSbQ) -* [344.反转字符串](https://mp.weixin.qq.com/s/_rNm66OJVl92gBDIbGpA3w) +* [27.移除元素](https://programmercarl.com/0027.移除元素.html) +* [15.三数之和](https://programmercarl.com/0015.三数之和.html) +* [18.四数之和](https://programmercarl.com/0018.四数之和.html) +* [206.翻转链表](https://programmercarl.com/0206.翻转链表.html) +* [142.环形链表II](https://programmercarl.com/0142.环形链表II.html) +* [344.反转字符串](https://programmercarl.com/0344.反转字符串.html) # 拓展 @@ -264,6 +264,49 @@ javaScript: }; ``` +Swift: + +```swift +func replaceSpace(_ s: String) -> String { + var strArr = Array(s) + var count = 0 + + // 统计空格的个数 + for i in strArr { + if i == " " { + count += 1 + } + } + // left 指向旧数组的最后一个元素 + var left = strArr.count - 1 + // right 指向扩容后数组的最后一个元素(这里还没对数组进行实际上的扩容) + var right = strArr.count + count * 2 - 1 + + // 实际对数组扩容 + for _ in 0..<(count * 2) { + strArr.append(" ") + } + + while left < right { + if strArr[left] == " " { + strArr[right] = "0" + strArr[right - 1] = "2" + strArr[right - 2] = "%" + left -= 1 + right -= 3 + } else { + strArr[right] = strArr[left] + left -= 1 + right -= 1 + } + } + + return String(strArr) +} +``` + + + ----------------------- diff --git a/problems/剑指Offer58-II.左旋转字符串.md b/problems/剑指Offer58-II.左旋转字符串.md index 15607a50..f4d3368c 100644 --- a/problems/剑指Offer58-II.左旋转字符串.md +++ b/problems/剑指Offer58-II.左旋转字符串.md @@ -11,11 +11,10 @@ # 题目:剑指Offer58-II.左旋转字符串 -https://leetcode-cn.com/problems/zuo-xuan-zhuan-zi-fu-chuan-lcof/ +[力扣题目链接](https://leetcode-cn.com/problems/zuo-xuan-zhuan-zi-fu-chuan-lcof/) 字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。请定义一个函数实现字符串左旋转操作的功能。比如,输入字符串"abcdefg"和数字2,该函数将返回左旋转两位得到的结果"cdefgab"。 - 示例 1: 输入: s = "abcdefg", k = 2 输出: "cdefgab" @@ -34,7 +33,7 @@ https://leetcode-cn.com/problems/zuo-xuan-zhuan-zi-fu-chuan-lcof/ 不能使用额外空间的话,模拟在本串操作要实现左旋转字符串的功能还是有点困难的。 -那么我们可以想一下上一题目[字符串:花式反转还不够!](https://mp.weixin.qq.com/s/4j6vPFHkFAXnQhmSkq2X9g)中讲过,使用整体反转+局部反转就可以实现,反转单词顺序的目的。 +那么我们可以想一下上一题目[字符串:花式反转还不够!](https://programmercarl.com/0151.翻转字符串里的单词.html)中讲过,使用整体反转+局部反转就可以实现,反转单词顺序的目的。 这道题目也非常类似,依然可以通过局部反转+整体反转 达到左旋转的目的。 @@ -76,13 +75,13 @@ public: 此时我们已经反转好多次字符串了,来一起回顾一下吧。 -在这篇文章[344.反转字符串](https://mp.weixin.qq.com/s/_rNm66OJVl92gBDIbGpA3w),第一次讲到反转一个字符串应该怎么做,使用了双指针法。 +在这篇文章[344.反转字符串](https://programmercarl.com/0344.反转字符串.html),第一次讲到反转一个字符串应该怎么做,使用了双指针法。 -然后发现[541. 反转字符串II](https://mp.weixin.qq.com/s/pzXt6PQ029y7bJ9YZB2mVQ),这里开始给反转加上了一些条件,当需要固定规律一段一段去处理字符串的时候,要想想在在for循环的表达式上做做文章。 +然后发现[541. 反转字符串II](https://programmercarl.com/0541.反转字符串II.html),这里开始给反转加上了一些条件,当需要固定规律一段一段去处理字符串的时候,要想想在在for循环的表达式上做做文章。 -后来在[151.翻转字符串里的单词](https://mp.weixin.qq.com/s/4j6vPFHkFAXnQhmSkq2X9g)中,要对一句话里的单词顺序进行反转,发现先整体反转再局部反转 是一个很妙的思路。 +后来在[151.翻转字符串里的单词](https://programmercarl.com/0151.翻转字符串里的单词.html)中,要对一句话里的单词顺序进行反转,发现先整体反转再局部反转 是一个很妙的思路。 -最后再讲到本题,本题则是先局部反转再 整体反转,与[151.翻转字符串里的单词](https://mp.weixin.qq.com/s/4j6vPFHkFAXnQhmSkq2X9g)类似,但是也是一种新的思路。 +最后再讲到本题,本题则是先局部反转再 整体反转,与[151.翻转字符串里的单词](https://programmercarl.com/0151.翻转字符串里的单词.html)类似,但是也是一种新的思路。 好了,反转字符串一共就介绍到这里,相信大家此时对反转字符串的常见操作已经很了解了。 diff --git a/problems/动态规划-股票问题总结篇.md b/problems/动态规划-股票问题总结篇.md index d186aaf9..a3443ecb 100644 --- a/problems/动态规划-股票问题总结篇.md +++ b/problems/动态规划-股票问题总结篇.md @@ -10,16 +10,16 @@ ![股票问题总结](https://code-thinking.cdn.bcebos.com/pics/%E8%82%A1%E7%A5%A8%E9%97%AE%E9%A2%98%E6%80%BB%E7%BB%93.jpg) -* [动态规划:121.买卖股票的最佳时机](https://mp.weixin.qq.com/s/keWo5qYJY4zmHn3amfXdfQ) -* [动态规划:122.买卖股票的最佳时机II](https://mp.weixin.qq.com/s/d4TRWFuhaY83HPa6t5ZL-w) -* [动态规划:123.买卖股票的最佳时机III](https://mp.weixin.qq.com/s/Sbs157mlVDtAR0gbLpdKzg) -* [动态规划:188.买卖股票的最佳时机IV](https://mp.weixin.qq.com/s/jtxZJWAo2y5sUsW647Z5cw) -* [动态规划:309.最佳买卖股票时机含冷冻期](https://mp.weixin.qq.com/s/TczJGFAPnkjH9ET8kwH1OA) -* [动态规划:714.买卖股票的最佳时机含手续费](https://mp.weixin.qq.com/s/2Cd_uINjerZ25VHH0K2IBQ) +* [动态规划:121.买卖股票的最佳时机](https://programmercarl.com/0121.买卖股票的最佳时机.html) +* [动态规划:122.买卖股票的最佳时机II](https://programmercarl.com/0122.买卖股票的最佳时机II(动态规划).html) +* [动态规划:123.买卖股票的最佳时机III](https://programmercarl.com/0123.买卖股票的最佳时机III.html) +* [动态规划:188.买卖股票的最佳时机IV](https://programmercarl.com/0188.买卖股票的最佳时机IV.html) +* [动态规划:309.最佳买卖股票时机含冷冻期](https://programmercarl.com/0309.最佳买卖股票时机含冷冻期.html) +* [动态规划:714.买卖股票的最佳时机含手续费](https://programmercarl.com/0714.买卖股票的最佳时机含手续费(动态规划).html) ## 卖股票的最佳时机 -[动态规划:121.买卖股票的最佳时机](https://mp.weixin.qq.com/s/keWo5qYJY4zmHn3amfXdfQ),**股票只能买卖一次,问最大利润**。 +[动态规划:121.买卖股票的最佳时机](https://programmercarl.com/0121.买卖股票的最佳时机.html),**股票只能买卖一次,问最大利润**。 【贪心解法】 @@ -103,7 +103,7 @@ public: ## 买卖股票的最佳时机II -[动态规划:122.买卖股票的最佳时机II](https://mp.weixin.qq.com/s/d4TRWFuhaY83HPa6t5ZL-w)可以多次买卖股票,问最大收益。 +[动态规划:122.买卖股票的最佳时机II](https://programmercarl.com/0122.买卖股票的最佳时机II(动态规划).html)可以多次买卖股票,问最大收益。 【贪心解法】 @@ -138,9 +138,9 @@ dp数组定义: * 第i-1天就持有股票,那么就保持现状,所得现金就是昨天持有股票的所得现金 即:dp[i - 1][0] * 第i天买入股票,所得现金就是昨天不持有股票的所得现金减去 今天的股票价格 即:dp[i - 1][1] - prices[i] -**注意这里和[121. 买卖股票的最佳时机](https://mp.weixin.qq.com/s/keWo5qYJY4zmHn3amfXdfQ)唯一不同的地方,就是推导dp[i][0]的时候,第i天买入股票的情况**。 +**注意这里和[121. 买卖股票的最佳时机](https://programmercarl.com/0121.买卖股票的最佳时机.html)唯一不同的地方,就是推导dp[i][0]的时候,第i天买入股票的情况**。 -在[121. 买卖股票的最佳时机](https://mp.weixin.qq.com/s/keWo5qYJY4zmHn3amfXdfQ)中,因为股票全程只能买卖一次,所以如果买入股票,那么第i天持有股票即dp[i][0]一定就是 -prices[i]。 +在[121. 买卖股票的最佳时机](https://programmercarl.com/0121.买卖股票的最佳时机.html)中,因为股票全程只能买卖一次,所以如果买入股票,那么第i天持有股票即dp[i][0]一定就是 -prices[i]。 而本题,因为一只股票可以买卖多次,所以当第i天买入股票的时候,所持有的现金可能有之前买卖过的利润。 @@ -169,7 +169,7 @@ public: ## 买卖股票的最佳时机III -[动态规划:123.买卖股票的最佳时机III](https://mp.weixin.qq.com/s/Sbs157mlVDtAR0gbLpdKzg)最多买卖两次,问最大收益。 +[动态规划:123.买卖股票的最佳时机III](https://programmercarl.com/0123.买卖股票的最佳时机III.html)最多买卖两次,问最大收益。 【动态规划】 @@ -257,7 +257,7 @@ public: ## 买卖股票的最佳时机IV -[动态规划:188.买卖股票的最佳时机IV](https://mp.weixin.qq.com/s/jtxZJWAo2y5sUsW647Z5cw) 最多买卖k笔交易,问最大收益。 +[动态规划:188.买卖股票的最佳时机IV](https://programmercarl.com/0188.买卖股票的最佳时机IV.html) 最多买卖k笔交易,问最大收益。 使用二维数组 dp[i][j] :第i天的状态为j,所剩下的最大现金是dp[i][j] @@ -325,12 +325,12 @@ public: ## 最佳买卖股票时机含冷冻期 -[动态规划:309.最佳买卖股票时机含冷冻期](https://mp.weixin.qq.com/s/TczJGFAPnkjH9ET8kwH1OA) 可以多次买卖但每次卖出有冷冻期1天。 +[动态规划:309.最佳买卖股票时机含冷冻期](https://programmercarl.com/0309.最佳买卖股票时机含冷冻期.html)可以多次买卖但每次卖出有冷冻期1天。 -相对于[动态规划:122.买卖股票的最佳时机II](https://mp.weixin.qq.com/s/d4TRWFuhaY83HPa6t5ZL-w),本题加上了一个冷冻期。 +相对于[动态规划:122.买卖股票的最佳时机II](https://programmercarl.com/0122.买卖股票的最佳时机II(动态规划).html),本题加上了一个冷冻期。 -在[动态规划:122.买卖股票的最佳时机II](https://mp.weixin.qq.com/s/d4TRWFuhaY83HPa6t5ZL-w) 中有两个状态,持有股票后的最多现金,和不持有股票的最多现金。本题则可以花费为四个状态 +在[动态规划:122.买卖股票的最佳时机II](https://programmercarl.com/0122.买卖股票的最佳时机II(动态规划).html) 中有两个状态,持有股票后的最多现金,和不持有股票的最多现金。本题则可以花费为四个状态 dp[i][j]:第i天状态为j,所剩的最多现金为dp[i][j]。 @@ -408,10 +408,10 @@ public: ## 买卖股票的最佳时机含手续费 -[动态规划:714.买卖股票的最佳时机含手续费](https://mp.weixin.qq.com/s/2Cd_uINjerZ25VHH0K2IBQ) 可以多次买卖,但每次有手续费。 +[动态规划:714.买卖股票的最佳时机含手续费](https://programmercarl.com/0714.买卖股票的最佳时机含手续费(动态规划).html) 可以多次买卖,但每次有手续费。 -相对于[动态规划:122.买卖股票的最佳时机II](https://mp.weixin.qq.com/s/d4TRWFuhaY83HPa6t5ZL-w),本题只需要在计算卖出操作的时候减去手续费就可以了,代码几乎是一样的。 +相对于[动态规划:122.买卖股票的最佳时机II](https://programmercarl.com/0122.买卖股票的最佳时机II(动态规划).html),本题只需要在计算卖出操作的时候减去手续费就可以了,代码几乎是一样的。 唯一差别在于递推公式部分,所以本篇也就不按照动规五部曲详细讲解了,主要讲解一下递推公式部分。 @@ -435,7 +435,7 @@ dp[i][1] 表示第i天不持有股票所得最多现金 所以:dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] + prices[i] - fee); -**本题和[动态规划:122.买卖股票的最佳时机II](https://mp.weixin.qq.com/s/d4TRWFuhaY83HPa6t5ZL-w)的区别就是这里需要多一个减去手续费的操作**。 +**本题和[动态规划:122.买卖股票的最佳时机II](https://programmercarl.com/0122.买卖股票的最佳时机II(动态规划).html)的区别就是这里需要多一个减去手续费的操作**。 以上分析完毕,代码如下: diff --git a/problems/动态规划总结篇.md b/problems/动态规划总结篇.md index d1c52005..e7e57351 100644 --- a/problems/动态规划总结篇.md +++ b/problems/动态规划总结篇.md @@ -10,7 +10,7 @@ 如今动态规划已经讲解了42道经典题目,共50篇文章,是时候做一篇总结了。 -关于动态规划,在专题第一篇[关于动态规划,你该了解这些!](https://mp.weixin.qq.com/s/ocZwfPlCWrJtVGACqFNAag)就说了动规五部曲,**而且强调了五部对解动规题目至关重要!** +关于动态规划,在专题第一篇[关于动态规划,你该了解这些!](https://programmercarl.com/动态规划理论基础.html)就说了动规五部曲,**而且强调了五部对解动规题目至关重要!** 这是Carl做过一百多道动规题目总结出来的经验结晶啊,如果大家跟着「代码随想哦」刷过动规专题,一定会对这动规五部曲的作用感受极其深刻。 @@ -35,7 +35,7 @@ 动规五部曲里,哪一部没想清楚,这道题目基本就做不出来,即使做出来了也没有想清楚,而是朦朦胧胧的就把题目过了。 * 如果想不清楚dp数组的具体含义,递归公式从何谈起,甚至初始化的时候就写错了。 -* 例如[动态规划:不同路径还不够,要有障碍!](https://mp.weixin.qq.com/s/lhqF0O4le9-wvalptOVOww) 在这道题目中,初始化才是重头戏 +* 例如[动态规划:不同路径还不够,要有障碍!](https://programmercarl.com/0063.不同路径II.html) 在这道题目中,初始化才是重头戏 * 如果看过背包系列,特别是完全背包,那么两层for循环先后顺序绝对可以搞懵很多人,反而递归公式是简单的。 * 至于推导dp数组的重要性,动规专题里几乎每篇Carl都反复强调,当程序结果不对的时候,一定要自己推导公式,看看和程序打印的日志是否一样。 @@ -43,72 +43,72 @@ ## 动划基础 -* [关于动态规划,你该了解这些!](https://mp.weixin.qq.com/s/ocZwfPlCWrJtVGACqFNAag) -* [动态规划:斐波那契数](https://mp.weixin.qq.com/s/ko0zLJplF7n_4TysnPOa_w) -* [动态规划:爬楼梯](https://mp.weixin.qq.com/s/Ohop0jApSII9xxOMiFhGIw) -* [动态规划:使用最小花费爬楼梯](https://mp.weixin.qq.com/s/djZB9gkyLFAKcQcSvKDorA) -* [动态规划:不同路径](https://mp.weixin.qq.com/s/MGgGIt4QCpFMROE9X9he_A) -* [动态规划:不同路径还不够,要有障碍!](https://mp.weixin.qq.com/s/lhqF0O4le9-wvalptOVOww) -* [动态规划:整数拆分,你要怎么拆?](https://mp.weixin.qq.com/s/cVbyHrsWH_Rfzlj-ESr01A) -* [动态规划:不同的二叉搜索树](https://mp.weixin.qq.com/s/8VE8pDrGxTf8NEVYBDwONw) +* [关于动态规划,你该了解这些!](https://programmercarl.com/动态规划理论基础.html) +* [动态规划:斐波那契数](https://programmercarl.com/0509.斐波那契数.html) +* [动态规划:爬楼梯](https://programmercarl.com/0070.爬楼梯.html) +* [动态规划:使用最小花费爬楼梯](https://programmercarl.com/0746.使用最小花费爬楼梯.html) +* [动态规划:不同路径](https://programmercarl.com/0062.不同路径.html) +* [动态规划:不同路径还不够,要有障碍!](https://programmercarl.com/0063.不同路径II.html) +* [动态规划:整数拆分,你要怎么拆?](https://programmercarl.com/0343.整数拆分.html) +* [动态规划:不同的二叉搜索树](https://programmercarl.com/0096.不同的二叉搜索树.html) ## 背包问题系列 背包问题大纲 -* [动态规划:关于01背包问题,你该了解这些!](https://mp.weixin.qq.com/s/FwIiPPmR18_AJO5eiidT6w) -* [动态规划:关于01背包问题,你该了解这些!(滚动数组)](https://mp.weixin.qq.com/s/M4uHxNVKRKm5HPjkNZBnFA) -* [动态规划:分割等和子集可以用01背包!](https://mp.weixin.qq.com/s/sYw3QtPPQ5HMZCJcT4EaLQ) -* [动态规划:最后一块石头的重量 II](https://mp.weixin.qq.com/s/WbwAo3jaUaNJjvhHgq0BGg) -* [动态规划:目标和!](https://mp.weixin.qq.com/s/2pWmaohX75gwxvBENS-NCw) -* [动态规划:一和零!](https://mp.weixin.qq.com/s/x-u3Dsp76DlYqtCe0xEKJw) -* [动态规划:关于完全背包,你该了解这些!](https://mp.weixin.qq.com/s/akwyxlJ4TLvKcw26KB9uJw) -* [动态规划:给你一些零钱,你要怎么凑?](https://mp.weixin.qq.com/s/PlowDsI4WMBOzf3q80AksQ) -* [动态规划:Carl称它为排列总和!](https://mp.weixin.qq.com/s/Iixw0nahJWQgbqVNk8k6gA) -* [动态规划:以前我没得选,现在我选择再爬一次!](https://mp.weixin.qq.com/s/e_wacnELo-2PG76EjrUakA) -* [动态规划: 给我个机会,我再兑换一次零钱](https://mp.weixin.qq.com/s/dyk-xNilHzNtVdPPLObSeQ) -* [动态规划:一样的套路,再求一次完全平方数](https://mp.weixin.qq.com/s/VfJT78p7UGpDZsapKF_QJQ) -* [动态规划:单词拆分](https://mp.weixin.qq.com/s/3Spx1B6MbIYjS8YkVbByzA) -* [动态规划:关于多重背包,你该了解这些!](https://mp.weixin.qq.com/s/b-UUUmbvG7URWyCjQkiuuQ) -* [听说背包问题很难? 这篇总结篇来拯救你了](https://mp.weixin.qq.com/s/ZOehl3U1mDiyOQjFG1wNJA) +* [动态规划:关于01背包问题,你该了解这些!](https://programmercarl.com/背包理论基础01背包-1.html) +* [动态规划:关于01背包问题,你该了解这些!(滚动数组)](https://programmercarl.com/背包理论基础01背包-2.html) +* [动态规划:分割等和子集可以用01背包!](https://programmercarl.com/0416.分割等和子集.html) +* [动态规划:最后一块石头的重量 II](https://programmercarl.com/1049.最后一块石头的重量II.html) +* [动态规划:目标和!](https://programmercarl.com/0494.目标和.html) +* [动态规划:一和零!](https://programmercarl.com/0474.一和零.html) +* [动态规划:关于完全背包,你该了解这些!](https://programmercarl.com/背包问题理论基础完全背包.html) +* [动态规划:给你一些零钱,你要怎么凑?](https://programmercarl.com/0518.零钱兑换II.html) +* [动态规划:Carl称它为排列总和!](https://programmercarl.com/0377.组合总和Ⅳ.html) +* [动态规划:以前我没得选,现在我选择再爬一次!](https://programmercarl.com/0070.爬楼梯完全背包版本.html) +* [动态规划: 给我个机会,我再兑换一次零钱](https://programmercarl.com/0322.零钱兑换.html) +* [动态规划:一样的套路,再求一次完全平方数](https://programmercarl.com/0279.完全平方数.html) +* [动态规划:单词拆分](https://programmercarl.com/0139.单词拆分.html) +* [动态规划:关于多重背包,你该了解这些!](https://programmercarl.com/背包问题理论基础多重背包.html) +* [听说背包问题很难? 这篇总结篇来拯救你了](https://programmercarl.com/背包总结篇.html) ## 打家劫舍系列 -* [动态规划:开始打家劫舍!](https://mp.weixin.qq.com/s/UZ31WdLEEFmBegdgLkJ8Dw) -* [动态规划:继续打家劫舍!](https://mp.weixin.qq.com/s/kKPx4HpH3RArbRcxAVHbeQ) -* [动态规划:还要打家劫舍!](https://mp.weixin.qq.com/s/BOJ1lHsxbQxUZffXlgglEQ) +* [动态规划:开始打家劫舍!](https://programmercarl.com/0198.打家劫舍.html) +* [动态规划:继续打家劫舍!](https://programmercarl.com/0213.打家劫舍II.html) +* [动态规划:还要打家劫舍!](https://programmercarl.com/0337.打家劫舍III.html) ## 股票系列 股票问题总结 -* [动态规划:买卖股票的最佳时机](https://mp.weixin.qq.com/s/keWo5qYJY4zmHn3amfXdfQ) -* [动态规划:本周我们都讲了这些(系列六)](https://mp.weixin.qq.com/s/GVu-6eF0iNkpVDKRXTPOTA) -* [动态规划:买卖股票的最佳时机II](https://mp.weixin.qq.com/s/d4TRWFuhaY83HPa6t5ZL-w) -* [动态规划:买卖股票的最佳时机III](https://mp.weixin.qq.com/s/Sbs157mlVDtAR0gbLpdKzg) -* [动态规划:买卖股票的最佳时机IV](https://mp.weixin.qq.com/s/jtxZJWAo2y5sUsW647Z5cw) -* [动态规划:最佳买卖股票时机含冷冻期](https://mp.weixin.qq.com/s/TczJGFAPnkjH9ET8kwH1OA) -* [动态规划:本周我们都讲了这些(系列七)](https://mp.weixin.qq.com/s/vdzDlrEvhXWRzblTnOnzKg) -* [动态规划:买卖股票的最佳时机含手续费](https://mp.weixin.qq.com/s/2Cd_uINjerZ25VHH0K2IBQ) -* [动态规划:股票系列总结篇](https://mp.weixin.qq.com/s/sC5XyEtDQWkonKnbCvZhDw) +* [动态规划:买卖股票的最佳时机](https://programmercarl.com/0121.买卖股票的最佳时机.html) +* [动态规划:本周我们都讲了这些(系列六)](https://programmercarl.com/周总结/20210225动规周末总结.html) +* [动态规划:买卖股票的最佳时机II](https://programmercarl.com/0122.买卖股票的最佳时机II(动态规划).html) +* [动态规划:买卖股票的最佳时机III](https://programmercarl.com/0123.买卖股票的最佳时机III.html) +* [动态规划:买卖股票的最佳时机IV](https://programmercarl.com/0188.买卖股票的最佳时机IV.html) +* [动态规划:最佳买卖股票时机含冷冻期](https://programmercarl.com/0309.最佳买卖股票时机含冷冻期.html) +* [动态规划:本周我们都讲了这些(系列七)](https://programmercarl.com/周总结/20210304动规周末总结.html) +* [动态规划:买卖股票的最佳时机含手续费](https://programmercarl.com/0714.买卖股票的最佳时机含手续费(动态规划).html) +* [动态规划:股票系列总结篇](https://programmercarl.com/动态规划-股票问题总结篇.html) ## 子序列系列 -* [动态规划:最长递增子序列](https://mp.weixin.qq.com/s/f8nLO3JGfgriXep_gJQpqQ) -* [动态规划:最长连续递增序列](https://mp.weixin.qq.com/s/c0Nn0TtjkTISVdqRsyMmyA) -* [动态规划:最长重复子数组](https://mp.weixin.qq.com/s/U5WaWqBwdoxzQDotOdWqZg) -* [动态规划:最长公共子序列](https://mp.weixin.qq.com/s/Qq0q4HaE4TyasCTj2WGFOg) -* [动态规划:不相交的线](https://mp.weixin.qq.com/s/krfYzSYEO8jIoVfyHzR0rw) -* [动态规划:最大子序和](https://mp.weixin.qq.com/s/2Xtyi2L4r8sM-BcxgUKmcA) -* [动态规划:判断子序列](https://mp.weixin.qq.com/s/2pjT4B4fjfOx5iB6N6xyng) -* [动态规划:不同的子序列](https://mp.weixin.qq.com/s/1SULY2XVSROtk_hsoVLu8A) -* [动态规划:两个字符串的删除操作](https://mp.weixin.qq.com/s/a8BerpqSf76DCqkPDJrpYg) -* [动态规划:编辑距离](https://mp.weixin.qq.com/s/8aG71XjSgZG6kZbiAdkJnQ) -* [为了绝杀编辑距离,我做了三步铺垫,你都知道么?](https://mp.weixin.qq.com/s/kbs4kCUzg8gPFttF9H3Yyw) -* [动态规划:回文子串](https://mp.weixin.qq.com/s/2WetyP6IYQ6VotegepVpEw) -* [动态规划:最长回文子序列](https://mp.weixin.qq.com/s/jbd3p4QPm5Kh1s2smTzWag) +* [动态规划:最长递增子序列](https://programmercarl.com/0300.最长上升子序列.html) +* [动态规划:最长连续递增序列](https://programmercarl.com/0674.最长连续递增序列.html) +* [动态规划:最长重复子数组](https://programmercarl.com/0718.最长重复子数组.html) +* [动态规划:最长公共子序列](https://programmercarl.com/1143.最长公共子序列.html) +* [动态规划:不相交的线](https://programmercarl.com/1035.不相交的线.html) +* [动态规划:最大子序和](https://programmercarl.com/0053.最大子序和(动态规划).html) +* [动态规划:判断子序列](https://programmercarl.com/0392.判断子序列.html) +* [动态规划:不同的子序列](https://programmercarl.com/0115.不同的子序列.html) +* [动态规划:两个字符串的删除操作](https://programmercarl.com/0583.两个字符串的删除操作.html) +* [动态规划:编辑距离](https://programmercarl.com/0072.编辑距离.html) +* [为了绝杀编辑距离,我做了三步铺垫,你都知道么?](https://programmercarl.com/为了绝杀编辑距离,卡尔做了三步铺垫.html) +* [动态规划:回文子串](https://programmercarl.com/0647.回文子串.html) +* [动态规划:最长回文子序列](https://programmercarl.com/0516.最长回文子序列.html) ## 动规结束语 diff --git a/problems/动态规划理论基础.md b/problems/动态规划理论基础.md index c9491da1..fd7977a6 100644 --- a/problems/动态规划理论基础.md +++ b/problems/动态规划理论基础.md @@ -12,7 +12,7 @@ 所以动态规划中每一个状态一定是由上一个状态推导出来的,**这一点就区分于贪心**,贪心没有状态推导,而是从局部直接选最优的, -在[关于贪心算法,你该了解这些!](https://mp.weixin.qq.com/s/O935TaoHE9Eexwe_vSbRAg)中我举了一个背包问题的例子。 +在[关于贪心算法,你该了解这些!](https://programmercarl.com/贪心算法理论基础.html)中我举了一个背包问题的例子。 例如:有N件物品和一个最多能背重量为W 的背包。第i件物品的重量是weight[i],得到的价值是value[i] 。**每件物品只能用一次**,求解将哪些物品装入背包里物品价值总和最大。 diff --git a/problems/双指针总结.md b/problems/双指针总结.md index df7cffae..11d6ffa4 100644 --- a/problems/双指针总结.md +++ b/problems/双指针总结.md @@ -12,7 +12,7 @@ # 数组篇 -在[数组:就移除个元素很难么?](https://mp.weixin.qq.com/s/RMkulE4NIb6XsSX83ra-Ww)中,原地移除数组上的元素,我们说到了数组上的元素,不能真正的删除,只能覆盖。 +在[数组:就移除个元素很难么?](https://programmercarl.com/0027.移除元素.html)中,原地移除数组上的元素,我们说到了数组上的元素,不能真正的删除,只能覆盖。 一些同学可能会写出如下代码(伪代码): @@ -30,11 +30,11 @@ for (int i = 0; i < array.size(); i++) { # 字符串篇 -在[字符串:这道题目,使用库函数一行代码搞定](https://mp.weixin.qq.com/s/_rNm66OJVl92gBDIbGpA3w)中讲解了反转字符串,注意这里强调要原地反转,要不然就失去了题目的意义。 +在[字符串:这道题目,使用库函数一行代码搞定](https://programmercarl.com/0344.反转字符串.html)中讲解了反转字符串,注意这里强调要原地反转,要不然就失去了题目的意义。 使用双指针法,**定义两个指针(也可以说是索引下表),一个从字符串前面,一个从字符串后面,两个指针同时向中间移动,并交换元素。**,时间复杂度是O(n)。 -在[替换空格](https://mp.weixin.qq.com/s/69HNjR4apcRSAo_KyknPjA) 中介绍使用双指针填充字符串的方法,如果想把这道题目做到极致,就不要只用额外的辅助空间了! +在[替换空格](https://programmercarl.com/剑指Offer05.替换空格.html) 中介绍使用双指针填充字符串的方法,如果想把这道题目做到极致,就不要只用额外的辅助空间了! 思路就是**首先扩充数组到每个空格替换成"%20"之后的大小。然后双指针从后向前替换空格。** @@ -44,7 +44,7 @@ for (int i = 0; i < array.size(); i++) { **其实很多数组(字符串)填充类的问题,都可以先预先给数组扩容带填充后的大小,然后在从后向前进行操作。** -那么在[字符串:花式反转还不够!](https://mp.weixin.qq.com/s/4j6vPFHkFAXnQhmSkq2X9g)中,我们使用双指针法,用O(n)的时间复杂度完成字符串删除类的操作,因为题目要产出冗余空格。 +那么在[字符串:花式反转还不够!](https://programmercarl.com/0151.翻转字符串里的单词.html)中,我们使用双指针法,用O(n)的时间复杂度完成字符串删除类的操作,因为题目要产出冗余空格。 **在删除冗余空格的过程中,如果不注意代码效率,很容易写成了O(n^2)的时间复杂度。其实使用双指针法O(n)就可以搞定。** @@ -54,19 +54,19 @@ for (int i = 0; i < array.size(); i++) { 翻转链表是现场面试,白纸写代码的好题,考察了候选者对链表以及指针的熟悉程度,而且代码也不长,适合在白纸上写。 -在[链表:听说过两天反转链表又写不出来了?](https://mp.weixin.qq.com/s/ckEvIVGcNLfrz6OLOMoT0A)中,讲如何使用双指针法来翻转链表,**只需要改变链表的next指针的指向,直接将链表反转 ,而不用重新定义一个新的链表。** +在[链表:听说过两天反转链表又写不出来了?](https://programmercarl.com/0206.翻转链表.html)中,讲如何使用双指针法来翻转链表,**只需要改变链表的next指针的指向,直接将链表反转 ,而不用重新定义一个新的链表。** 思路还是很简单的,代码也不长,但是想在白纸上一次性写出bugfree的代码,并不是容易的事情。 -在链表中求环,应该是双指针在链表里最经典的应用,在[链表:环找到了,那入口呢?](https://mp.weixin.qq.com/s/gt_VH3hQTqNxyWcl1ECSbQ)中讲解了如何通过双指针判断是否有环,而且还要找到环的入口。 +在链表中求环,应该是双指针在链表里最经典的应用,在[链表:环找到了,那入口呢?](https://programmercarl.com/0142.环形链表II.html)中讲解了如何通过双指针判断是否有环,而且还要找到环的入口。 **使用快慢指针(双指针法),分别定义 fast 和 slow指针,从头结点出发,fast指针每次移动两个节点,slow指针每次移动一个节点,如果 fast 和 slow指针在途中相遇 ,说明这个链表有环。** -那么找到环的入口,其实需要点简单的数学推理,我在文章中把找环的入口清清楚楚的推理的一遍,如果对找环入口不够清楚的同学建议自己看一看[链表:环找到了,那入口呢?](https://mp.weixin.qq.com/s/gt_VH3hQTqNxyWcl1ECSbQ)。 +那么找到环的入口,其实需要点简单的数学推理,我在文章中把找环的入口清清楚楚的推理的一遍,如果对找环入口不够清楚的同学建议自己看一看[链表:环找到了,那入口呢?](https://programmercarl.com/0142.环形链表II.html)。 # N数之和篇 -在[哈希表:解决了两数之和,那么能解决三数之和么?](https://mp.weixin.qq.com/s/QfTNEByq1YlNSXRKEumwHg)中,讲到使用哈希法可以解决1.两数之和的问题 +在[哈希表:解决了两数之和,那么能解决三数之和么?](https://programmercarl.com/0015.三数之和.html)中,讲到使用哈希法可以解决1.两数之和的问题 其实使用双指针也可以解决1.两数之和的问题,只不过1.两数之和求的是两个元素的下标,没法用双指针,如果改成求具体两个元素的数值就可以了,大家可以尝试用双指针做一个leetcode上两数之和的题目,就可以体会到我说的意思了。 @@ -82,7 +82,7 @@ for (int i = 0; i < array.size(); i++) { 只用双指针法时间复杂度为O(n^2),但比哈希法的O(n^2)效率高得多,哈希法在使用两层for循环的时候,能做的剪枝操作很有限。 -在[双指针法:一样的道理,能解决四数之和](https://mp.weixin.qq.com/s/SBU3THi1Kv6Sar7htqCB2Q)中,讲到了四数之和,其实思路是一样的,**在三数之和的基础上再套一层for循环,依然是使用双指针法。** +在[双指针法:一样的道理,能解决四数之和](https://programmercarl.com/0018.四数之和.html)中,讲到了四数之和,其实思路是一样的,**在三数之和的基础上再套一层for循环,依然是使用双指针法。** 对于三数之和使用双指针法就是将原本暴力O(n^3)的解法,降为O(n^2)的解法,四数之和的双指针解法就是将原本暴力O(n^4)的解法,降为O(n^3)的解法。 diff --git a/problems/周总结/20200927二叉树周末总结.md b/problems/周总结/20200927二叉树周末总结.md index f81cc6bb..5a7e398a 100644 --- a/problems/周总结/20200927二叉树周末总结.md +++ b/problems/周总结/20200927二叉树周末总结.md @@ -7,7 +7,7 @@ ## 周一 -本周我们开始讲解了二叉树,在[关于二叉树,你该了解这些!](https://mp.weixin.qq.com/s/_ymfWYvTNd2GvWvC5HOE4A)中讲解了二叉树的理论基础。 +本周我们开始讲解了二叉树,在[关于二叉树,你该了解这些!](https://programmercarl.com/二叉树理论基础.html)中讲解了二叉树的理论基础。 有同学会把红黑树和二叉平衡搜索树弄分开了,其实红黑树就是一种二叉平衡搜索树,这两个树不是独立的,所以C++中map、multimap、set、multiset的底层实现机制是二叉平衡搜索树,再具体一点是红黑树。 @@ -48,9 +48,9 @@ morris遍历是二叉树遍历算法的超强进阶算法,morris遍历可以 ## 周二 -在[二叉树:一入递归深似海,从此offer是路人](https://mp.weixin.qq.com/s/PwVIfxDlT3kRgMASWAMGhA)中讲到了递归三要素,以及前中后序的递归写法。 +在[二叉树:一入递归深似海,从此offer是路人](https://programmercarl.com/二叉树的递归遍历.html)中讲到了递归三要素,以及前中后序的递归写法。 -文章中我给出了leetcode上三道二叉树的前中后序题目,但是看完[二叉树:一入递归深似海,从此offer是路人](https://mp.weixin.qq.com/s/PwVIfxDlT3kRgMASWAMGhA),依然可以解决n叉树的前后序遍历,在leetcode上分别是 +文章中我给出了leetcode上三道二叉树的前中后序题目,但是看完[二叉树:一入递归深似海,从此offer是路人](https://programmercarl.com/二叉树的递归遍历.html),依然可以解决n叉树的前后序遍历,在leetcode上分别是 * 589. N叉树的前序遍历 * 590. N叉树的后序遍历 @@ -58,7 +58,7 @@ morris遍历是二叉树遍历算法的超强进阶算法,morris遍历可以 ## 周三 -在[二叉树:听说递归能做的,栈也能做!](https://mp.weixin.qq.com/s/c_zCrGHIVlBjUH_hJtghCg)中我们开始用栈来实现递归的写法,也就是所谓的迭代法。 +在[二叉树:听说递归能做的,栈也能做!](https://programmercarl.com/二叉树的迭代遍历.html)中我们开始用栈来实现递归的写法,也就是所谓的迭代法。 细心的同学发现文中前后序遍历空节点是否入栈写法是不同的 @@ -121,7 +121,7 @@ public: ## 周四 -在[二叉树:前中后序迭代方式的写法就不能统一一下么?](https://mp.weixin.qq.com/s/WKg0Ty1_3SZkztpHubZPRg)中我们使用空节点作为标记,给出了统一的前中后序迭代法。 +在[二叉树:前中后序迭代方式的写法就不能统一一下么?](https://programmercarl.com/二叉树的统一迭代法.html)中我们使用空节点作为标记,给出了统一的前中后序迭代法。 此时又多了一种前中后序的迭代写法,那么有同学问了:前中后序迭代法是不是一定要统一来写,这样才算是规范。 @@ -131,7 +131,7 @@ public: ## 周五 -在[二叉树:层序遍历登场!](https://mp.weixin.qq.com/s/Gb3BjakIKGNpup2jYtTzog)中我们介绍了二叉树的另一种遍历方式(图论中广度优先搜索在二叉树上的应用)即:层序遍历。 +在[二叉树:层序遍历登场!](https://programmercarl.com/0102.二叉树的层序遍历.html)中我们介绍了二叉树的另一种遍历方式(图论中广度优先搜索在二叉树上的应用)即:层序遍历。 看完这篇文章,去leetcode上怒刷五题,文章中 编号107题目的样例图放错了(原谅我匆忙之间总是手抖),但不影响大家理解。 @@ -141,7 +141,7 @@ public: ## 周六 -在[二叉树:你真的会翻转二叉树么?](https://mp.weixin.qq.com/s/6gY1MiXrnm-khAAJiIb5Bg)中我们把翻转二叉树这么一道简单又经典的问题,充分的剖析了一波,相信就算做过这道题目的同学,看完本篇之后依然有所收获! +在[二叉树:你真的会翻转二叉树么?](https://programmercarl.com/0226.翻转二叉树.html)中我们把翻转二叉树这么一道简单又经典的问题,充分的剖析了一波,相信就算做过这道题目的同学,看完本篇之后依然有所收获! **文中我指的是递归的中序遍历是不行的,因为使用递归的中序遍历,某些节点的左右孩子会翻转两次。** diff --git a/problems/周总结/20201003二叉树周末总结.md b/problems/周总结/20201003二叉树周末总结.md index db89fc82..a0b8c2dd 100644 --- a/problems/周总结/20201003二叉树周末总结.md +++ b/problems/周总结/20201003二叉树周末总结.md @@ -7,7 +7,7 @@ ## 周一 -本周刚开始我们讲解了判断二叉树是否对称的写法, [二叉树:我对称么?](https://mp.weixin.qq.com/s/Kgf0gjvlDlNDfKIH2b1Oxg)。 +本周刚开始我们讲解了判断二叉树是否对称的写法, [二叉树:我对称么?](https://programmercarl.com/0101.对称二叉树.html)。 这道题目的本质是要比较两个树(这两个树是根节点的左右子树),遍历两棵树而且要比较内侧和外侧节点,所以准确的来说是一个树的遍历顺序是左右中,一个树的遍历顺序是右左中。 @@ -17,7 +17,7 @@ * 100.相同的树 * 572.另一个树的子树 -**[二叉树:我对称么?](https://mp.weixin.qq.com/s/Kgf0gjvlDlNDfKIH2b1Oxg)中的递归法和迭代法只需要稍作修改其中一个树的遍历顺序,便可刷了100.相同的树。** +**[二叉树:我对称么?](https://programmercarl.com/0101.对称二叉树.html)中的递归法和迭代法只需要稍作修改其中一个树的遍历顺序,便可刷了100.相同的树。** 100.相同的树的递归代码如下: @@ -102,11 +102,11 @@ public: ## 周二 -在[二叉树:看看这些树的最大深度](https://mp.weixin.qq.com/s/guKwV-gSNbA1CcbvkMtHBg)中,我们讲解了如何求二叉树的最大深度。 +在[二叉树:看看这些树的最大深度](https://programmercarl.com/0104.二叉树的最大深度.html)中,我们讲解了如何求二叉树的最大深度。 本题可以使用前序,也可以使用后序遍历(左右中),使用前序求的就是深度,使用后序呢求的是高度。 -**而根节点的高度就是二叉树的最大深度**,所以本题中我们通过后序求的根节点高度来求的二叉树最大深度,所以[二叉树:看看这些树的最大深度](https://mp.weixin.qq.com/s/guKwV-gSNbA1CcbvkMtHBg)中使用的是后序遍历。 +**而根节点的高度就是二叉树的最大深度**,所以本题中我们通过后序求的根节点高度来求的二叉树最大深度,所以[二叉树:看看这些树的最大深度](https://programmercarl.com/0104.二叉树的最大深度.html)中使用的是后序遍历。 本题当然也可以使用前序,代码如下:(**充分表现出求深度回溯的过程**) ```CPP @@ -169,7 +169,7 @@ public: ## 周三 -在[二叉树:看看这些树的最小深度](https://mp.weixin.qq.com/s/BH8-gPC3_QlqICDg7rGSGA)中,我们讲解如何求二叉树的最小深度, 这道题目要是稍不留心很容易犯错。 +在[二叉树:看看这些树的最小深度](https://programmercarl.com/0111.二叉树的最小深度.html)中,我们讲解如何求二叉树的最小深度, 这道题目要是稍不留心很容易犯错。 **注意这里最小深度是从根节点到最近叶子节点的最短路径上的节点数量。注意是叶子节点。** @@ -177,19 +177,19 @@ public: **求二叉树的最小深度和求二叉树的最大深度的差别主要在于处理左右孩子不为空的逻辑。** -注意到这一点之后 递归法和迭代法 都可以参照[二叉树:看看这些树的最大深度](https://mp.weixin.qq.com/s/guKwV-gSNbA1CcbvkMtHBg)写出来。 +注意到这一点之后 递归法和迭代法 都可以参照[二叉树:看看这些树的最大深度](https://programmercarl.com/0104.二叉树的最大深度.html)写出来。 ## 周四 -我们在[二叉树:我有多少个节点?](https://mp.weixin.qq.com/s/2_eAjzw-D0va9y4RJgSmXw)中,讲解了如何求二叉树的节点数量。 +我们在[二叉树:我有多少个节点?](https://programmercarl.com/0222.完全二叉树的节点个数.html)中,讲解了如何求二叉树的节点数量。 -这一天是十一长假的第一天,又是双节,所以简单一些,只要把之前两篇[二叉树:看看这些树的最大深度](https://mp.weixin.qq.com/s/guKwV-gSNbA1CcbvkMtHBg), [二叉树:看看这些树的最小深度](https://mp.weixin.qq.com/s/BH8-gPC3_QlqICDg7rGSGA)都认真看了的话,这道题目可以分分钟刷掉了。 +这一天是十一长假的第一天,又是双节,所以简单一些,只要把之前两篇[二叉树:看看这些树的最大深度](https://programmercarl.com/0104.二叉树的最大深度.html), [二叉树:看看这些树的最小深度](https://programmercarl.com/0111.二叉树的最小深度.html)都认真看了的话,这道题目可以分分钟刷掉了。 估计此时大家对这一类求二叉树节点数量以及求深度应该非常熟练了。 ## 周五 -在[二叉树:我平衡么?](https://mp.weixin.qq.com/s/isUS-0HDYknmC0Rr4R8mww)中讲解了如何判断二叉树是否是平衡二叉树 +在[二叉树:我平衡么?](https://programmercarl.com/0110.平衡二叉树.html)中讲解了如何判断二叉树是否是平衡二叉树 今天讲解一道判断平衡二叉树的题目,其实 方法上我们之前讲解深度的时候都讲过了,但是这次我们通过这道题目彻底搞清楚二叉树高度与深度的问题,以及对应的遍历方式。 @@ -212,7 +212,7 @@ public: ## 周六 -在[二叉树:找我的所有路径?](https://mp.weixin.qq.com/s/Osw4LQD2xVUnCJ-9jrYxJA)中正式涉及到了回溯,很多同学过了这道题目,可能都不知道自己使用了回溯,其实回溯和递归都是相伴相生的。最后我依然给出了迭代法的版本。 +在[二叉树:找我的所有路径?](https://programmercarl.com/0257.二叉树的所有路径.html)中正式涉及到了回溯,很多同学过了这道题目,可能都不知道自己使用了回溯,其实回溯和递归都是相伴相生的。最后我依然给出了迭代法的版本。 我在题解中第一个版本的代码会把回溯的过程充分体现出来,如果大家直接看简洁的代码版本,很可能就会忽略的回溯的存在。 diff --git a/problems/周总结/20201010二叉树周末总结.md b/problems/周总结/20201010二叉树周末总结.md index 7b1e7f68..913ad963 100644 --- a/problems/周总结/20201010二叉树周末总结.md +++ b/problems/周总结/20201010二叉树周末总结.md @@ -4,7 +4,7 @@ ## 周一 -在[二叉树:以为使用了递归,其实还隐藏着回溯](https://mp.weixin.qq.com/s/ivLkHzWdhjQQD1rQWe6zWA)中,通过leetcode [257.二叉树的所有路径这道题目](https://mp.weixin.qq.com/s/Osw4LQD2xVUnCJ-9jrYxJA),讲解了递归如何隐藏着回溯,一些代码会把回溯的过程都隐藏了起来了,甚至刷过这道题的同学可能都不知道自己用了回溯。 +在[二叉树:以为使用了递归,其实还隐藏着回溯](https://programmercarl.com/二叉树中递归带着回溯.html)中,通过leetcode [257.二叉树的所有路径这道题目](https://programmercarl.com/0257.二叉树的所有路径.html),讲解了递归如何隐藏着回溯,一些代码会把回溯的过程都隐藏了起来了,甚至刷过这道题的同学可能都不知道自己用了回溯。 文章中第一版代码把每一个细节都展示了输出来了,大家可以清晰的看到回溯的过程。 @@ -15,7 +15,7 @@ ## 周二 -在文章[二叉树:做了这么多题目了,我的左叶子之和是多少?](https://mp.weixin.qq.com/s/gBAgmmFielojU5Wx3wqFTA) 中提供了另一个判断节点属性的思路,平时我们习惯了使用通过节点的左右孩子判断本节点的属性,但发现使用这个思路无法判断左叶子。 +在文章[二叉树:做了这么多题目了,我的左叶子之和是多少?](https://programmercarl.com/0404.左叶子之和.html) 中提供了另一个判断节点属性的思路,平时我们习惯了使用通过节点的左右孩子判断本节点的属性,但发现使用这个思路无法判断左叶子。 此时需要相连的三层之间构成的约束条件,也就是要通过节点的父节点以及孩子节点来判断本节点的属性。 @@ -24,7 +24,7 @@ ## 周三 -在[二叉树:我的左下角的值是多少?](https://mp.weixin.qq.com/s/MH2gbLvzQ91jHPKqiub0Nw)中的题目如果使用递归的写法还是有点难度的,层次遍历反而很简单。 +在[二叉树:我的左下角的值是多少?](https://programmercarl.com/0513.找树左下角的值.html)中的题目如果使用递归的写法还是有点难度的,层次遍历反而很简单。 题目其实就是要在树的**最后一行**找到**最左边的值**。 @@ -32,26 +32,26 @@ 在这篇文章中,我们使用递归算法实实在在的求了一次深度,然后使用靠左的遍历,保证求得靠左的最大深度,而且又一次使用了回溯。 -如果对二叉树的高度与深度又有点模糊了,在看这里[二叉树:我平衡么?](https://mp.weixin.qq.com/s/isUS-0HDYknmC0Rr4R8mww),回忆一下吧。 +如果对二叉树的高度与深度又有点模糊了,在看这里[二叉树:我平衡么?](https://programmercarl.com/0110.平衡二叉树.html),回忆一下吧。 -[二叉树:我的左下角的值是多少?](https://mp.weixin.qq.com/s/MH2gbLvzQ91jHPKqiub0Nw)中把我们之前讲过的内容都过了一遍,此外,还用前序遍历的技巧求得了靠左的最大深度。 +[二叉树:我的左下角的值是多少?](https://programmercarl.com/0513.找树左下角的值.html)中把我们之前讲过的内容都过了一遍,此外,还用前序遍历的技巧求得了靠左的最大深度。 **求二叉树的各种最值,就想应该采用什么样的遍历顺序,确定了遍历循序,其实就和数组求最值一样容易了。** ## 周四 -在[二叉树:递归函数究竟什么时候需要返回值,什么时候不要返回值?](https://mp.weixin.qq.com/s/6TWAVjxQ34kVqROWgcRFOg)中通过两道题目,彻底说清楚递归函数的返回值问题。 +在[二叉树:递归函数究竟什么时候需要返回值,什么时候不要返回值?](https://programmercarl.com/0112.路径总和.html)中通过两道题目,彻底说清楚递归函数的返回值问题。 一般情况下:**如果需要搜索整颗二叉树,那么递归函数就不要返回值,如果要搜索其中一条符合条件的路径,递归函数就需要返回值,因为遇到符合条件的路径了就要及时返回。** 特别是有些时候 递归函数的返回值是bool类型,一些同学会疑惑为啥要加这个,其实就是为了找到一条边立刻返回。 -其实还有一种就是后序遍历需要根据左右递归的返回值推出中间节点的状态,这种需要有返回值,例如[222.完全二叉树](https://mp.weixin.qq.com/s/2_eAjzw-D0va9y4RJgSmXw),[110.平衡二叉树](https://mp.weixin.qq.com/s/isUS-0HDYknmC0Rr4R8mww),这几道我们之前也讲过。 +其实还有一种就是后序遍历需要根据左右递归的返回值推出中间节点的状态,这种需要有返回值,例如[222.完全二叉树](https://programmercarl.com/0222.完全二叉树的节点个数.html),[110.平衡二叉树](https://programmercarl.com/0110.平衡二叉树.html),这几道我们之前也讲过。 ## 周五 -之前都是讲解遍历二叉树,这次该构造二叉树了,在[二叉树:构造二叉树登场!](https://mp.weixin.qq.com/s/7r66ap2s-shvVvlZxo59xg)中,我们通过前序和中序,后序和中序,构造了唯一的一颗二叉树。 +之前都是讲解遍历二叉树,这次该构造二叉树了,在[二叉树:构造二叉树登场!](https://programmercarl.com/0106.从中序与后序遍历序列构造二叉树.html)中,我们通过前序和中序,后序和中序,构造了唯一的一颗二叉树。 **构造二叉树有三个注意的点:** @@ -65,7 +65,7 @@ ## 周六 -知道了如何构造二叉树,那么使用一个套路就可以解决文章[二叉树:构造一棵最大的二叉树](https://mp.weixin.qq.com/s/1iWJV6Aov23A7xCF4nV88w)中的问题。 +知道了如何构造二叉树,那么使用一个套路就可以解决文章[二叉树:构造一棵最大的二叉树](https://programmercarl.com/0654.最大二叉树.html)中的问题。 **注意类似用数组构造二叉树的题目,每次分隔尽量不要定义新的数组,而是通过下表索引直接在原数组上操作,这样可以节约时间和空间上的开销。** @@ -77,12 +77,12 @@ 本周我们深度讲解了如下知识点: -1. [递归中如何隐藏着回溯](https://mp.weixin.qq.com/s/ivLkHzWdhjQQD1rQWe6zWA) -2. [如何通过三层关系确定左叶子](https://mp.weixin.qq.com/s/gBAgmmFielojU5Wx3wqFTA) -3. [如何通过二叉树深度来判断左下角的值](https://mp.weixin.qq.com/s/MH2gbLvzQ91jHPKqiub0Nw) -4. [递归函数究竟什么时候需要返回值,什么时候不要返回值?](https://mp.weixin.qq.com/s/6TWAVjxQ34kVqROWgcRFOg) -5. [前序和中序,后序和中序构造唯一二叉树](https://mp.weixin.qq.com/s/7r66ap2s-shvVvlZxo59xg) -6. [使用数组构造某一特性的二叉树](https://mp.weixin.qq.com/s/1iWJV6Aov23A7xCF4nV88w) +1. [递归中如何隐藏着回溯](https://programmercarl.com/二叉树中递归带着回溯.html) +2. [如何通过三层关系确定左叶子](https://programmercarl.com/0404.左叶子之和.html) +3. [如何通过二叉树深度来判断左下角的值](https://programmercarl.com/0513.找树左下角的值.html) +4. [递归函数究竟什么时候需要返回值,什么时候不要返回值?](https://programmercarl.com/0112.路径总和.html) +5. [前序和中序,后序和中序构造唯一二叉树](https://programmercarl.com/0106.从中序与后序遍历序列构造二叉树.html) +6. [使用数组构造某一特性的二叉树](https://programmercarl.com/0654.最大二叉树.html) **如果大家一路跟下来,一定收获满满,如果周末不做这个总结,大家可能都不知道自己收获满满,啊哈!** diff --git a/problems/周总结/20201017二叉树周末总结.md b/problems/周总结/20201017二叉树周末总结.md index c061a48e..4b219834 100644 --- a/problems/周总结/20201017二叉树周末总结.md +++ b/problems/周总结/20201017二叉树周末总结.md @@ -6,9 +6,9 @@ ## 周一 -在[二叉树:合并两个二叉树](https://mp.weixin.qq.com/s/3f5fbjOFaOX_4MXzZ97LsQ)中讲解了如何合并两个二叉树,平时我们都习惯了操作一个二叉树,一起操作两个树可能还有点陌生。 +在[二叉树:合并两个二叉树](https://programmercarl.com/0617.合并二叉树.html)中讲解了如何合并两个二叉树,平时我们都习惯了操作一个二叉树,一起操作两个树可能还有点陌生。 -其实套路是一样,只不过一起操作两个树的指针,我们之前讲过求 [二叉树:我对称么?](https://mp.weixin.qq.com/s/Kgf0gjvlDlNDfKIH2b1Oxg)的时候,已经初步涉及到了 一起遍历两颗二叉树了。 +其实套路是一样,只不过一起操作两个树的指针,我们之前讲过求 [二叉树:我对称么?](https://programmercarl.com/0101.对称二叉树.html)的时候,已经初步涉及到了 一起遍历两颗二叉树了。 **迭代法中,一般一起操作两个树都是使用队列模拟类似层序遍历,同时处理两个树的节点,这种方式最好理解,如果用模拟递归的思路的话,要复杂一些。** @@ -16,7 +16,7 @@ 周二开始讲解一个新的树,二叉搜索树,开始要换一个思路了,如果没有利用好二叉搜索树的特性,就容易把简单题做成了难题了。 -学习[二叉搜索树的特性](https://mp.weixin.qq.com/s/vsKrWRlETxCVsiRr8v_hHg),还是比较容易的。 +学习[二叉搜索树的特性](https://programmercarl.com/0700.二叉搜索树中的搜索.html),还是比较容易的。 大多是二叉搜索树的题目,其实都离不开中序遍历,因为这样就是有序的。 @@ -24,7 +24,7 @@ ## 周三 -了解了二搜索树的特性之后, 开始验证[一颗二叉树是不是二叉搜索树](https://mp.weixin.qq.com/s/8odY9iUX5eSi0eRFSXFD4Q)。 +了解了二搜索树的特性之后, 开始验证[一颗二叉树是不是二叉搜索树](https://programmercarl.com/0098.验证二叉搜索树.html)。 首先在此强调一下二叉搜索树的特性: @@ -46,15 +46,15 @@ **在二叉树中通过两个前后指针作比较,会经常用到**。 -本文[二叉树:我是不是一棵二叉搜索树](https://mp.weixin.qq.com/s/8odY9iUX5eSi0eRFSXFD4Q)中迭代法中为什么没有周一那篇那么简洁了呢,因为本篇是验证二叉搜索树,前提默认它是一棵普通二叉树,所以还是要回归之前老办法。 +本文[二叉树:我是不是一棵二叉搜索树](https://programmercarl.com/0098.验证二叉搜索树.html)中迭代法中为什么没有周一那篇那么简洁了呢,因为本篇是验证二叉搜索树,前提默认它是一棵普通二叉树,所以还是要回归之前老办法。 ## 周四 -了解了[二叉搜索树](https://mp.weixin.qq.com/s/vsKrWRlETxCVsiRr8v_hHg),并且知道[如何判断二叉搜索树](https://mp.weixin.qq.com/s/8odY9iUX5eSi0eRFSXFD4Q),本篇就很简单了。 +了解了[二叉搜索树](https://programmercarl.com/0700.二叉搜索树中的搜索.html),并且知道[如何判断二叉搜索树](https://programmercarl.com/0098.验证二叉搜索树.html),本篇就很简单了。 **要知道二叉搜索树和中序遍历是好朋友!** -在[二叉树:搜索树的最小绝对差](https://mp.weixin.qq.com/s/Hwzml6698uP3qQCC1ctUQQ)中强调了要利用搜索树的特性,把这道题目想象成在一个有序数组上求两个数最小差值,这就是一道送分题了。 +在[二叉树:搜索树的最小绝对差](https://programmercarl.com/0530.二叉搜索树的最小绝对差.html)中强调了要利用搜索树的特性,把这道题目想象成在一个有序数组上求两个数最小差值,这就是一道送分题了。 **需要明确:在有序数组求任意两数最小值差等价于相邻两数的最小值差**。 @@ -64,7 +64,7 @@ 此时大家应该知道遇到二叉搜索树,就想是有序数组,那么在二叉搜索树中求二叉搜索树众数就很简单了。 -在[二叉树:我的众数是多少?](https://mp.weixin.qq.com/s/KSAr6OVQIMC-uZ8MEAnGHg)中我给出了如果是普通二叉树,应该如何求众数的集合,然后进一步讲解了二叉搜索树应该如何求众数集合。 +在[二叉树:我的众数是多少?](https://programmercarl.com/0501.二叉搜索树中的众数.html)中我给出了如果是普通二叉树,应该如何求众数的集合,然后进一步讲解了二叉搜索树应该如何求众数集合。 在求众数集合的时候有一个技巧,因为题目中众数是可以有多个的,所以一般的方法需要遍历两遍才能求出众数的集合。 @@ -74,7 +74,7 @@ ## 周六 -在[二叉树:公共祖先问题](https://mp.weixin.qq.com/s/n6Rk3nc_X3TSkhXHrVmBTQ)中,我们开始讲解如何在二叉树中求公共祖先的问题,本来是打算和二叉搜索树一起讲的,但发现篇幅过长,所以先讲二叉树的公共祖先问题。 +在[二叉树:公共祖先问题](https://programmercarl.com/0236.二叉树的最近公共祖先.html)中,我们开始讲解如何在二叉树中求公共祖先的问题,本来是打算和二叉搜索树一起讲的,但发现篇幅过长,所以先讲二叉树的公共祖先问题。 **如果找到一个节点,发现左子树出现结点p,右子树出现节点q,或者 左子树出现结点q,右子树出现节点p,那么该节点就是节点p和q的最近公共祖先。** @@ -92,13 +92,13 @@ ## 总结 -本周我们讲了[如何合并两个二叉树](https://mp.weixin.qq.com/s/3f5fbjOFaOX_4MXzZ97LsQ),了解了如何操作两个二叉树。 +本周我们讲了[如何合并两个二叉树](https://programmercarl.com/0617.合并二叉树.html),了解了如何操作两个二叉树。 -然后开始另一种树:二叉搜索树,了解[二叉搜索树的特性](https://mp.weixin.qq.com/s/vsKrWRlETxCVsiRr8v_hHg),然后[判断一棵二叉树是不是二叉搜索树](https://mp.weixin.qq.com/s/8odY9iUX5eSi0eRFSXFD4Q)。 +然后开始另一种树:二叉搜索树,了解[二叉搜索树的特性](https://programmercarl.com/0700.二叉搜索树中的搜索.html),然后[判断一棵二叉树是不是二叉搜索树](https://programmercarl.com/0098.验证二叉搜索树.html)。 -了解以上知识之后,就开始利用其特性,做一些二叉搜索树上的题目,[求最小绝对差](https://mp.weixin.qq.com/s/Hwzml6698uP3qQCC1ctUQQ),[求众数集合](https://mp.weixin.qq.com/s/KSAr6OVQIMC-uZ8MEAnGHg)。 +了解以上知识之后,就开始利用其特性,做一些二叉搜索树上的题目,[求最小绝对差](https://programmercarl.com/0530.二叉搜索树的最小绝对差.html),[求众数集合](https://programmercarl.com/0501.二叉搜索树中的众数.html)。 -接下来,开始求二叉树与二叉搜索树的公共祖先问题,单篇篇幅原因,先单独介绍[普通二叉树如何求最近公共祖先](https://mp.weixin.qq.com/s/n6Rk3nc_X3TSkhXHrVmBTQ)。 +接下来,开始求二叉树与二叉搜索树的公共祖先问题,单篇篇幅原因,先单独介绍[普通二叉树如何求最近公共祖先](https://programmercarl.com/0236.二叉树的最近公共祖先.html)。 现在已经讲过了几种二叉树了,二叉树,二叉平衡树,完全二叉树,二叉搜索树,后面还会有平衡二叉搜索树。 那么一些同学难免会有混乱了,我针对如下三个问题,帮大家在捋顺一遍: diff --git a/problems/周总结/20201030回溯周末总结.md b/problems/周总结/20201030回溯周末总结.md index 54cdc3b5..3a432bee 100644 --- a/problems/周总结/20201030回溯周末总结.md +++ b/problems/周总结/20201030回溯周末总结.md @@ -13,7 +13,7 @@ 本周我们正式开始了回溯算法系列,那么首先当然是概述。 -在[关于回溯算法,你该了解这些!](https://mp.weixin.qq.com/s/gjSgJbNbd1eAA5WkA-HeWw)中介绍了什么是回溯,回溯法的效率,回溯法解决的问题以及回溯法模板。 +在[关于回溯算法,你该了解这些!](https://programmercarl.com/回溯算法理论基础.html)中介绍了什么是回溯,回溯法的效率,回溯法解决的问题以及回溯法模板。 **回溯是递归的副产品,只要有递归就会有回溯**。 @@ -31,14 +31,14 @@ 回溯法确实不好理解,所以需要把回溯法抽象为一个图形来理解就容易多了,每一道回溯法的题目都可以抽象为树形结构。 -针对很多同学都写不好回溯,我在[关于回溯算法,你该了解这些!](https://mp.weixin.qq.com/s/gjSgJbNbd1eAA5WkA-HeWw)用回溯三部曲,分析了回溯算法,并给出了回溯法的模板。 +针对很多同学都写不好回溯,我在[关于回溯算法,你该了解这些!](https://programmercarl.com/回溯算法理论基础.html)用回溯三部曲,分析了回溯算法,并给出了回溯法的模板。 这个模板会伴随整个回溯法系列! ## 周二 -在[回溯算法:求组合问题!](https://mp.weixin.qq.com/s/OnBjbLzuipWz_u4QfmgcqQ)中,我们开始用回溯法解决第一道题目,组合问题。 +在[回溯算法:求组合问题!](https://programmercarl.com/0077.组合.html)中,我们开始用回溯法解决第一道题目,组合问题。 我在文中开始的时候给大家列举k层for循环例子,进而得出都是同样是暴利解法,为什么要用回溯法。 @@ -48,19 +48,19 @@ ## 周三 -针对[回溯算法:求组合问题!](https://mp.weixin.qq.com/s/OnBjbLzuipWz_u4QfmgcqQ)还可以做剪枝的操作。 +针对[回溯算法:求组合问题!](https://programmercarl.com/0077.组合.html)还可以做剪枝的操作。 -在[回溯算法:组合问题再剪剪枝](https://mp.weixin.qq.com/s/Ri7spcJMUmph4c6XjPWXQA)中把回溯法代码做了剪枝优化,在文中我依然把问题抽象为一个树形结构,大家可以一目了然剪的究竟是哪里。 +在[回溯算法:组合问题再剪剪枝](https://programmercarl.com/0077.组合优化.html)中把回溯法代码做了剪枝优化,在文中我依然把问题抽象为一个树形结构,大家可以一目了然剪的究竟是哪里。 **剪枝精髓是:for循环在寻找起点的时候要有一个范围,如果这个起点到集合终止之间的元素已经不够 题目要求的k个元素了,就没有必要搜索了**。 ## 周四 -在[回溯算法:求组合总和!](https://mp.weixin.qq.com/s/HX7WW6ixbFZJASkRnCTC3w)中,相当于 [回溯算法:求组合问题!](https://mp.weixin.qq.com/s/OnBjbLzuipWz_u4QfmgcqQ)加了一个元素总和的限制。 +在[回溯算法:求组合总和!](https://programmercarl.com/0216.组合总和III.html)中,相当于 [回溯算法:求组合问题!](https://programmercarl.com/0077.组合.html)加了一个元素总和的限制。 整体思路还是一样的,本题的剪枝会好想一些,即:**已选元素总和如果已经大于n(题中要求的和)了,那么往后遍历就没有意义了,直接剪掉**。 -在本题中,依然还可以有一个剪枝,就是[回溯算法:组合问题再剪剪枝](https://mp.weixin.qq.com/s/Ri7spcJMUmph4c6XjPWXQA)中提到的,对for循环选择的起始范围的剪枝。 +在本题中,依然还可以有一个剪枝,就是[回溯算法:组合问题再剪剪枝](https://programmercarl.com/0077.组合优化.html)中提到的,对for循环选择的起始范围的剪枝。 所以,剪枝的代码,可以把for循环,加上 `i <= 9 - (k - path.size()) + 1` 的限制! @@ -68,11 +68,11 @@ ## 周五 -在[回溯算法:电话号码的字母组合](https://mp.weixin.qq.com/s/e2ua2cmkE_vpYjM3j6HY0A)中,开始用多个集合来求组合,还是熟悉的模板题目,但是有一些细节。 +在[回溯算法:电话号码的字母组合](https://programmercarl.com/0017.电话号码的字母组合.html)中,开始用多个集合来求组合,还是熟悉的模板题目,但是有一些细节。 -例如这里for循环,可不像是在 [回溯算法:求组合问题!](https://mp.weixin.qq.com/s/OnBjbLzuipWz_u4QfmgcqQ)和[回溯算法:求组合总和!](https://mp.weixin.qq.com/s/HX7WW6ixbFZJASkRnCTC3w)中从startIndex开始遍历的。 +例如这里for循环,可不像是在 [回溯算法:求组合问题!](https://programmercarl.com/0077.组合.html)和[回溯算法:求组合总和!](https://programmercarl.com/0216.组合总和III.html)中从startIndex开始遍历的。 -**因为本题每一个数字代表的是不同集合,也就是求不同集合之间的组合,而[回溯算法:求组合问题!](https://mp.weixin.qq.com/s/OnBjbLzuipWz_u4QfmgcqQ)和[回溯算法:求组合总和!](https://mp.weixin.qq.com/s/HX7WW6ixbFZJASkRnCTC3w)都是是求同一个集合中的组合!** +**因为本题每一个数字代表的是不同集合,也就是求不同集合之间的组合,而[回溯算法:求组合问题!](https://programmercarl.com/0077.组合.html)和[回溯算法:求组合总和!](https://programmercarl.com/0216.组合总和III.html)都是是求同一个集合中的组合!** 如果大家在现场面试的时候,一定要注意各种输入异常的情况,例如本题输入1 * #按键。 @@ -82,9 +82,9 @@ 因为之前链表系列没有写总结,虽然链表系列已经是两个月前的事情,但还是有必要补一下。 -所以给出[链表:总结篇!](https://mp.weixin.qq.com/s/vK0JjSTHfpAbs8evz5hH8A),这里对之前链表理论基础和经典题目进行了总结。 +所以给出[链表:总结篇!](https://programmercarl.com/链表总结篇.html),这里对之前链表理论基础和经典题目进行了总结。 -同时对[链表:环找到了,那入口呢?](https://mp.weixin.qq.com/s/_QVP3IkRZWx9zIpQRgajzA)中求环入口的问题又进行了补充证明,可以说把环形链表的方方面面都讲的很通透了,大家如果没有做过环形链表的题目一定要去做一做。 +同时对[链表:环找到了,那入口呢?](https://programmercarl.com/0142.环形链表II.html)中求环入口的问题又进行了补充证明,可以说把环形链表的方方面面都讲的很通透了,大家如果没有做过环形链表的题目一定要去做一做。 ## 总结 diff --git a/problems/周总结/20201107回溯周末总结.md b/problems/周总结/20201107回溯周末总结.md index 66036f64..71bf62de 100644 --- a/problems/周总结/20201107回溯周末总结.md +++ b/problems/周总结/20201107回溯周末总结.md @@ -6,17 +6,17 @@ ## 周一 -在[回溯算法:求组合总和(二)](https://mp.weixin.qq.com/s/FLg8G6EjVcxBjwCbzpACPw)中讲解的组合总和问题,和以前的组合问题还都不一样。 +在[回溯算法:求组合总和(二)](https://programmercarl.com/0039.组合总和.html)中讲解的组合总和问题,和以前的组合问题还都不一样。 -本题和[回溯算法:求组合问题!](https://mp.weixin.qq.com/s/OnBjbLzuipWz_u4QfmgcqQ),[回溯算法:求组合总和!](https://mp.weixin.qq.com/s/HX7WW6ixbFZJASkRnCTC3w)和区别是:本题没有数量要求,可以无限重复,但是有总和的限制,所以间接的也是有个数的限制。 +本题和[回溯算法:求组合问题!](https://programmercarl.com/0077.组合.html),[回溯算法:求组合总和!](https://programmercarl.com/0216.组合总和III.html)和区别是:本题没有数量要求,可以无限重复,但是有总和的限制,所以间接的也是有个数的限制。 不少录友都是看到可以重复选择,就义无反顾的把startIndex去掉了。 **本题还需要startIndex来控制for循环的起始位置,对于组合问题,什么时候需要startIndex呢?** -我举过例子,如果是一个集合来求组合的话,就需要startIndex,例如:[回溯算法:求组合问题!](https://mp.weixin.qq.com/s/OnBjbLzuipWz_u4QfmgcqQ),[回溯算法:求组合总和!](https://mp.weixin.qq.com/s/HX7WW6ixbFZJASkRnCTC3w)。 +我举过例子,如果是一个集合来求组合的话,就需要startIndex,例如:[回溯算法:求组合问题!](https://programmercarl.com/0077.组合.html),[回溯算法:求组合总和!](https://programmercarl.com/0216.组合总和III.html)。 -如果是多个集合取组合,各个集合之间相互不影响,那么就不用startIndex,例如:[回溯算法:电话号码的字母组合](https://mp.weixin.qq.com/s/e2ua2cmkE_vpYjM3j6HY0A) +如果是多个集合取组合,各个集合之间相互不影响,那么就不用startIndex,例如:[回溯算法:电话号码的字母组合](https://programmercarl.com/0017.电话号码的字母组合.html) **注意以上我只是说求组合的情况,如果是排列问题,又是另一套分析的套路,后面我再讲解排列的时候就重点介绍**。 @@ -30,13 +30,13 @@ for (int i = startIndex; i < candidates.size() && sum + candidates[i] <= target; **在求和问题中,排序之后加剪枝是常见的套路!** -在[回溯算法:求组合总和(二)](https://mp.weixin.qq.com/s/FLg8G6EjVcxBjwCbzpACPw)第一个树形结构没有画出startIndex的作用,**这里这里纠正一下,准确的树形结构如图所示:** +在[回溯算法:求组合总和(二)](https://programmercarl.com/0039.组合总和.html)第一个树形结构没有画出startIndex的作用,**这里这里纠正一下,准确的树形结构如图所示:** ![39.组合总和](https://img-blog.csdnimg.cn/20201123202227835.png) ## 周二 -在[回溯算法:求组合总和(三)](https://mp.weixin.qq.com/s/_1zPYk70NvHsdY8UWVGXmQ)中依旧讲解组合总和问题,本题集合元素会有重复,但要求解集不能包含重复的组合。 +在[回溯算法:求组合总和(三)](https://programmercarl.com/0040.组合总和II.html)中依旧讲解组合总和问题,本题集合元素会有重复,但要求解集不能包含重复的组合。 **所以难就难在去重问题上了**。 @@ -60,7 +60,7 @@ for (int i = startIndex; i < candidates.size() && sum + candidates[i] <= target; ## 周三 -在[回溯算法:分割回文串](https://mp.weixin.qq.com/s/Pb1epUTbU8fHIht-g_MS5Q)中,我们开始讲解切割问题,虽然最后代码看起来好像是一道模板题,但是从分析到学会套用这个模板,是比较难的。 +在[回溯算法:分割回文串](https://programmercarl.com/0131.分割回文串.html)中,我们开始讲解切割问题,虽然最后代码看起来好像是一道模板题,但是从分析到学会套用这个模板,是比较难的。 我列出如下几个难点: @@ -85,9 +85,9 @@ for (int i = startIndex; i < candidates.size() && sum + candidates[i] <= target; ## 周四 -如果没有做过[回溯算法:分割回文串](https://mp.weixin.qq.com/s/Pb1epUTbU8fHIht-g_MS5Q)的话,[回溯算法:复原IP地址](https://mp.weixin.qq.com/s/v--VmA8tp9vs4bXCqHhBuA)这道题目应该是比较难的。 +如果没有做过[回溯算法:分割回文串](https://programmercarl.com/0131.分割回文串.html)的话,[回溯算法:复原IP地址](https://programmercarl.com/0093.复原IP地址.html)这道题目应该是比较难的。 -复原IP照[回溯算法:分割回文串](https://mp.weixin.qq.com/s/Pb1epUTbU8fHIht-g_MS5Q)就多了一些限制,例如只能分四段,而且还是更改字符串,插入逗点。 +复原IP照[回溯算法:分割回文串](https://programmercarl.com/0131.分割回文串.html)就多了一些限制,例如只能分四段,而且还是更改字符串,插入逗点。 树形图如下: @@ -109,7 +109,7 @@ if (s.size() > 12) return result; // 剪枝 ## 周五 -在[回溯算法:求子集问题!](https://mp.weixin.qq.com/s/NNRzX-vJ_pjK4qxohd_LtA)中讲解了子集问题,**在树形结构中子集问题是要收集所有节点的结果,而组合问题是收集叶子节点的结果**。 +在[回溯算法:求子集问题!](https://programmercarl.com/0078.子集.html)中讲解了子集问题,**在树形结构中子集问题是要收集所有节点的结果,而组合问题是收集叶子节点的结果**。 如图: @@ -135,13 +135,13 @@ if (startIndex >= nums.size()) { // 终止条件可以不加 ## 周六 -早起的哈希表系列没有总结,所以[哈希表:总结篇!(每逢总结必经典)](https://mp.weixin.qq.com/s/1s91yXtarL-PkX07BfnwLg)如约而至。 +早起的哈希表系列没有总结,所以[哈希表:总结篇!(每逢总结必经典)](https://programmercarl.com/哈希表总结.html)如约而至。 可能之前大家做过很多哈希表的题目,但是没有串成线,总结篇来帮你串成线,捋顺哈希表的整个脉络。 大家对什么时候各种set与map比较疑惑,想深入了解红黑树,哈希之类的。 -**如果真的只是想清楚什么时候使用各种set与map,不用看那么多,把[关于哈希表,你该了解这些!](https://mp.weixin.qq.com/s/g8N6WmoQmsCUw3_BaWxHZA)看了就够了**。 +**如果真的只是想清楚什么时候使用各种set与map,不用看那么多,把[关于哈希表,你该了解这些!](https://programmercarl.com/哈希表理论基础.html)看了就够了**。 ## 总结 diff --git a/problems/周总结/20201112回溯周末总结.md b/problems/周总结/20201112回溯周末总结.md index 9ca3cff1..3d019cf2 100644 --- a/problems/周总结/20201112回溯周末总结.md +++ b/problems/周总结/20201112回溯周末总结.md @@ -4,9 +4,9 @@ ## 周一 -在[回溯算法:求子集问题(二)](https://mp.weixin.qq.com/s/WJ4JNDRJgsW3eUN72Hh3uQ)中,开始针对子集问题进行去重。 +在[回溯算法:求子集问题(二)](https://programmercarl.com/0090.子集II.html)中,开始针对子集问题进行去重。 -本题就是[回溯算法:求子集问题!](https://mp.weixin.qq.com/s/NNRzX-vJ_pjK4qxohd_LtA)的基础上加上了去重,去重我们在[回溯算法:求组合总和(三)](https://mp.weixin.qq.com/s/_1zPYk70NvHsdY8UWVGXmQ)也讲过了。 +本题就是[回溯算法:求子集问题!](https://programmercarl.com/0078.子集.html)的基础上加上了去重,去重我们在[回溯算法:求组合总和(三)](https://programmercarl.com/0040.组合总和II.html)也讲过了。 所以本题对大家应该并不难。 @@ -16,18 +16,18 @@ ## 周二 -在[回溯算法:递增子序列](https://mp.weixin.qq.com/s/ePxOtX1ATRYJb2Jq7urzHQ)中,处处都能看到子集的身影,但处处是陷阱,值得好好琢磨琢磨! +在[回溯算法:递增子序列](https://programmercarl.com/0491.递增子序列.html)中,处处都能看到子集的身影,但处处是陷阱,值得好好琢磨琢磨! 树形结构如下: ![491. 递增子序列1](https://img-blog.csdnimg.cn/20201112170832333.png) -[回溯算法:递增子序列](https://mp.weixin.qq.com/s/ePxOtX1ATRYJb2Jq7urzHQ)留言区大家有很多疑问,主要还是和[回溯算法:求子集问题(二)](https://mp.weixin.qq.com/s/WJ4JNDRJgsW3eUN72Hh3uQ)混合在了一起。 +[回溯算法:递增子序列](https://programmercarl.com/0491.递增子序列.html)留言区大家有很多疑问,主要还是和[回溯算法:求子集问题(二)](https://programmercarl.com/0090.子集II.html)混合在了一起。 详细在[本周小结!(回溯算法系列三)续集](https://mp.weixin.qq.com/s/kSMGHc_YpsqL2j-jb_E_Ag)中给出了介绍! ## 周三 -我们已经分析了组合问题,分割问题,子集问题,那么[回溯算法:排列问题!](https://mp.weixin.qq.com/s/SCOjeMX1t41wcvJq49GhMw) 又不一样了。 +我们已经分析了组合问题,分割问题,子集问题,那么[回溯算法:排列问题!](https://programmercarl.com/0046.全排列.html) 又不一样了。 排列是有序的,也就是说[1,2] 和[2,1] 是两个集合,这和之前分析的子集以及组合所不同的地方。 @@ -43,7 +43,7 @@ ## 周四 -排列问题也要去重了,在[回溯算法:排列问题(二)](https://mp.weixin.qq.com/s/9L8h3WqRP_h8LLWNT34YlA)中又一次强调了“树层去重”和“树枝去重”。 +排列问题也要去重了,在[回溯算法:排列问题(二)](https://programmercarl.com/0047.全排列II.html)中又一次强调了“树层去重”和“树枝去重”。 树形结构如下: @@ -87,9 +87,9 @@ ## 总结 -本周我们对[子集问题进行了去重](https://mp.weixin.qq.com/s/WJ4JNDRJgsW3eUN72Hh3uQ),然后介绍了和子集问题非常像的[递增子序列](https://mp.weixin.qq.com/s/ePxOtX1ATRYJb2Jq7urzHQ),如果还保持惯性思维,这道题就可以掉坑里。 +本周我们对[子集问题进行了去重](https://programmercarl.com/0090.子集II.html),然后介绍了和子集问题非常像的[递增子序列](https://programmercarl.com/0491.递增子序列.html),如果还保持惯性思维,这道题就可以掉坑里。 -接着介绍了[排列问题!](https://mp.weixin.qq.com/s/SCOjeMX1t41wcvJq49GhMw),以及对[排列问题如何进行去重](https://mp.weixin.qq.com/s/9L8h3WqRP_h8LLWNT34YlA)。 +接着介绍了[排列问题!](https://programmercarl.com/0046.全排列.html),以及对[排列问题如何进行去重](https://programmercarl.com/0047.全排列II.html)。 最后我补充了子集问题,排列问题和组合问题的性能分析,给大家提供了回溯算法复杂度的分析思路。 diff --git a/problems/周总结/20201126贪心周末总结.md b/problems/周总结/20201126贪心周末总结.md index ea504991..5671cdbd 100644 --- a/problems/周总结/20201126贪心周末总结.md +++ b/problems/周总结/20201126贪心周末总结.md @@ -3,7 +3,7 @@ ## 周一 -本周正式开始了贪心算法,在[关于贪心算法,你该了解这些!](https://mp.weixin.qq.com/s/O935TaoHE9Eexwe_vSbRAg)中,我们介绍了什么是贪心以及贪心的套路。 +本周正式开始了贪心算法,在[关于贪心算法,你该了解这些!](https://programmercarl.com/贪心算法理论基础.html)中,我们介绍了什么是贪心以及贪心的套路。 **贪心的本质是选择每一阶段的局部最优,从而达到全局最优。** @@ -25,7 +25,7 @@ ## 周二 -在[贪心算法:分发饼干](https://mp.weixin.qq.com/s/YSuLIAYyRGlyxbp9BNC1uw)中讲解了贪心算法的第一道题目。 +在[贪心算法:分发饼干](https://programmercarl.com/0455.分发饼干.html)中讲解了贪心算法的第一道题目。 这道题目很明显能看出来是用贪心,也是入门好题。 @@ -39,7 +39,7 @@ 所有还是小饼干优先先喂饱小胃口更好一些,也比较直观。 -一些录友不清楚[贪心算法:分发饼干](https://mp.weixin.qq.com/s/YSuLIAYyRGlyxbp9BNC1uw)中时间复杂度是怎么来的? +一些录友不清楚[贪心算法:分发饼干](https://programmercarl.com/0455.分发饼干.html)中时间复杂度是怎么来的? 就是快排O(nlogn),遍历O(n),加一起就是还是O(nlogn)。 @@ -47,7 +47,7 @@ 接下来就要上一点难度了,要不然大家会误以为贪心算法就是常识判断一下就行了。 -在[贪心算法:摆动序列](https://mp.weixin.qq.com/s/Xytl05kX8LZZ1iWWqjMoHA)中,需要计算最长摇摆序列。 +在[贪心算法:摆动序列](https://programmercarl.com/0376.摆动序列.html)中,需要计算最长摇摆序列。 其实就是让序列有尽可能多的局部峰值。 @@ -62,13 +62,13 @@ ## 周四 -在[贪心算法:最大子序和](https://mp.weixin.qq.com/s/DrjIQy6ouKbpletQr0g1Fg)中,详细讲解了用贪心的方式来求最大子序列和,其实这道题目是一道动态规划的题目。 +在[贪心算法:最大子序和](https://programmercarl.com/0053.最大子序和.html)中,详细讲解了用贪心的方式来求最大子序列和,其实这道题目是一道动态规划的题目。 **贪心的思路为局部最优:当前“连续和”为负数的时候立刻放弃,从下一个元素重新计算“连续和”,因为负数加上下一个元素 “连续和”只会越来越小。从而推出全局最优:选取最大“连续和”** 代码很简单,但是思路却比较难。还需要反复琢磨。 -针对[贪心算法:最大子序和](https://mp.weixin.qq.com/s/DrjIQy6ouKbpletQr0g1Fg)文章中给出的贪心代码如下; +针对[贪心算法:最大子序和](https://programmercarl.com/0053.最大子序和.html)文章中给出的贪心代码如下; ``` class Solution { public: @@ -95,17 +95,17 @@ public: ## 总结 -本周我们讲解了[贪心算法的理论基础](https://mp.weixin.qq.com/s/O935TaoHE9Eexwe_vSbRAg),了解了贪心本质:局部最优推出全局最优。 +本周我们讲解了[贪心算法的理论基础](https://programmercarl.com/贪心算法理论基础.html),了解了贪心本质:局部最优推出全局最优。 -然后讲解了第一道题目[分发饼干](https://mp.weixin.qq.com/s/YSuLIAYyRGlyxbp9BNC1uw),还是比较基础的,可能会给大家一种贪心算法比较简单的错觉,因为贪心有时候接近于常识。 +然后讲解了第一道题目[分发饼干](https://programmercarl.com/0455.分发饼干.html),还是比较基础的,可能会给大家一种贪心算法比较简单的错觉,因为贪心有时候接近于常识。 其实我还准备一些简单的贪心题目,甚至网上很多都质疑这些题目是不是贪心算法。这些题目我没有立刻发出来,因为真的会让大家感觉贪心过于简单,而忽略了贪心的本质:局部最优和全局最优两个关键点。 **所以我在贪心系列难度会有所交替,难的题目在于拓展思路,简单的题目在于分析清楚其贪心的本质,后续我还会发一些简单的题目来做贪心的分析。** -在[摆动序列](https://mp.weixin.qq.com/s/Xytl05kX8LZZ1iWWqjMoHA)中大家就初步感受到贪心没那么简单了。 +在[摆动序列](https://programmercarl.com/0376.摆动序列.html)中大家就初步感受到贪心没那么简单了。 -本周最后是[最大子序和](https://mp.weixin.qq.com/s/DrjIQy6ouKbpletQr0g1Fg),这道题目要用贪心的方式做出来,就比较有难度,都知道负数加上正数之后会变小,但是这道题目依然会让很多人搞混淆,其关键在于:**不能让“连续和”为负数的时候加上下一个元素,而不是 不让“连续和”加上一个负数**。这块真的需要仔细体会! +本周最后是[最大子序和](https://programmercarl.com/0053.最大子序和.html),这道题目要用贪心的方式做出来,就比较有难度,都知道负数加上正数之后会变小,但是这道题目依然会让很多人搞混淆,其关键在于:**不能让“连续和”为负数的时候加上下一个元素,而不是 不让“连续和”加上一个负数**。这块真的需要仔细体会! diff --git a/problems/周总结/20201203贪心周末总结.md b/problems/周总结/20201203贪心周末总结.md index a82c5d4a..23b0b7cf 100644 --- a/problems/周总结/20201203贪心周末总结.md +++ b/problems/周总结/20201203贪心周末总结.md @@ -6,7 +6,7 @@ 一说到股票问题,一般都会想到动态规划,其实有时候贪心更有效! -在[贪心算法:买卖股票的最佳时机II](https://mp.weixin.qq.com/s/VsTFA6U96l18Wntjcg3fcg)中,讲到只能多次买卖一支股票,如何获取最大利润。 +在[贪心算法:买卖股票的最佳时机II](https://programmercarl.com/0122.买卖股票的最佳时机II.html)中,讲到只能多次买卖一支股票,如何获取最大利润。 **这道题目理解利润拆分是关键点!** 不要整块的去看,而是把整体利润拆为每天的利润,就很容易想到贪心了。 @@ -20,7 +20,7 @@ ## 周二 -在[贪心算法:跳跃游戏](https://mp.weixin.qq.com/s/606_N9j8ACKCODoCbV1lSA)中是给你一个数组看能否跳到终点。 +在[贪心算法:跳跃游戏](https://programmercarl.com/0055.跳跃游戏.html)中是给你一个数组看能否跳到终点。 本题贪心的关键是:**不用拘泥于每次究竟跳几步,而是看覆盖范围,覆盖范围内一定是可以跳过来的,不用管是怎么跳的**。 @@ -37,7 +37,7 @@ ## 周三 -这道题目:[贪心算法:跳跃游戏II](https://mp.weixin.qq.com/s/kJBcsJ46DKCSjT19pxrNYg)可就有点难了。 +这道题目:[贪心算法:跳跃游戏II](https://programmercarl.com/0045.跳跃游戏II.html)可就有点难了。 本题解题关键在于:**以最小的步数增加最大的覆盖范围,直到覆盖范围覆盖了终点**。 @@ -49,7 +49,7 @@ 注意:**图中的移动下标是到当前这步覆盖的最远距离(下标2的位置),此时没有到终点,只能增加第二步来扩大覆盖范围**。 -在[贪心算法:跳跃游戏II](https://mp.weixin.qq.com/s/kJBcsJ46DKCSjT19pxrNYg)中我给出了两个版本的代码。 +在[贪心算法:跳跃游戏II](https://programmercarl.com/0045.跳跃游戏II.html)中我给出了两个版本的代码。 其实本质都是超过当前覆盖范围,步数就加一,但版本一需要考虑当前覆盖最远距离下标是不是数组终点的情况。 @@ -67,7 +67,7 @@ ## 周四 -这道题目:[贪心算法:K次取反后最大化的数组和](https://mp.weixin.qq.com/s/dMTzBBVllRm_Z0aaWvYazA)就比较简单了,哈哈,用简单题来讲一讲贪心的思想。 +这道题目:[贪心算法:K次取反后最大化的数组和](https://programmercarl.com/1005.K次取反后最大化的数组和.html)就比较简单了,哈哈,用简单题来讲一讲贪心的思想。 **这里其实用了两次贪心!** @@ -77,8 +77,7 @@ 第二次贪心:局部最优:只找数值最小的正整数进行反转,当前数值可以达到最大(例如正整数数组{5, 3, 1},反转1 得到-1 比 反转5得到的-5 大多了),全局最优:整个 数组和 达到最大。 - -[贪心算法:K次取反后最大化的数组和](https://mp.weixin.qq.com/s/dMTzBBVllRm_Z0aaWvYazA)中的代码,最后while处理K的时候,其实直接判断奇偶数就可以了,文中给出的方式太粗暴了,哈哈,Carl大意了。 +[贪心算法:K次取反后最大化的数组和](https://programmercarl.com/1005.K次取反后最大化的数组和.html)中的代码,最后while处理K的时候,其实直接判断奇偶数就可以了,文中给出的方式太粗暴了,哈哈,Carl大意了。 例外一位录友留言给出一个很好的建议,因为文中是使用快排,仔细看题,**题目中限定了数据范围是正负一百,所以可以使用桶排序**,这样时间复杂度就可以优化为O(n)了。但可能代码要复杂一些了。 diff --git a/problems/周总结/20201210复杂度分析周末总结.md b/problems/周总结/20201210复杂度分析周末总结.md index 8fe13f0b..02bfbd83 100644 --- a/problems/周总结/20201210复杂度分析周末总结.md +++ b/problems/周总结/20201210复杂度分析周末总结.md @@ -15,7 +15,7 @@ # 周一 -在[程序员的简历应该这么写!!(附简历模板)](https://mp.weixin.qq.com/s/nCTUzuRTBo1_R_xagVszsA)中以我自己的总结经验为例讲一讲大家应该如何写简历。 +在[程序员的简历应该这么写!!(附简历模板)](https://programmercarl.com/前序/程序员简历.html)中以我自己的总结经验为例讲一讲大家应该如何写简历。 主要有如下几点: @@ -49,7 +49,7 @@ # 周二 -在[关于时间复杂度,你不知道的都在这里!](https://mp.weixin.qq.com/s/LWBfehW1gMuEnXtQjJo-sw)中详细讲解了时间复杂度,很多被大家忽略的内容,在文中都做了详细的解释。 +在[关于时间复杂度,你不知道的都在这里!](https://programmercarl.com/前序/关于时间复杂度,你不知道的都在这里!.html)中详细讲解了时间复杂度,很多被大家忽略的内容,在文中都做了详细的解释。 文中涉及如下问题: @@ -61,7 +61,7 @@ 这些问题大家可能懵懵懂懂的了解一些,但一细问又答不上来。 -相信看完本篇[关于时间复杂度,你不知道的都在这里!](https://mp.weixin.qq.com/s/LWBfehW1gMuEnXtQjJo-sw),以上问题大家就理解的清晰多了。 +相信看完本篇[关于时间复杂度,你不知道的都在这里!](https://programmercarl.com/前序/关于时间复杂度,你不知道的都在这里!.html),以上问题大家就理解的清晰多了。 文中最后还运用以上知识通过一道简单的题目具体分析了一下其时间复杂度,给出两种方法究竟谁最优。 @@ -70,7 +70,7 @@ # 周三 -在[O(n)的算法居然超时了,此时的n究竟是多大?](https://mp.weixin.qq.com/s/73ryNsuPFvBQkt6BbhNzLA)中介绍了大家在leetcode上提交代码经常遇到的一个问题-超时! +在[O(n)的算法居然超时了,此时的n究竟是多大?](https://programmercarl.com/前序/On的算法居然超时了,此时的n究竟是多大?.html)中介绍了大家在leetcode上提交代码经常遇到的一个问题-超时! 估计很多录友知道算法超时了,但没有注意过 O(n)的算法,如果1s内出结果,这个n究竟是多大? @@ -85,7 +85,7 @@ # 周四 -在[通过一道面试题目,讲一讲递归算法的时间复杂度!](https://mp.weixin.qq.com/s/I6ZXFbw09NR31F5CJR_geQ)中,讲一讲如果计算递归算法的时间复杂度。 +在[通过一道面试题目,讲一讲递归算法的时间复杂度!](https://programmercarl.com/前序/通过一道面试题目,讲一讲递归算法的时间复杂度!.html)中,讲一讲如果计算递归算法的时间复杂度。 递归的时间复杂度等于**递归的次数 * 每次递归中的操作次数**。 diff --git a/problems/周总结/20201217贪心周末总结.md b/problems/周总结/20201217贪心周末总结.md index 4363027c..4d12f92a 100644 --- a/problems/周总结/20201217贪心周末总结.md +++ b/problems/周总结/20201217贪心周末总结.md @@ -6,7 +6,7 @@ ## 周一 -在[贪心算法:加油站](https://mp.weixin.qq.com/s/aDbiNuEZIhy6YKgQXvKELw)中给出每一个加油站的汽油和开到这个加油站的消耗,问汽车能不能开一圈。 +在[贪心算法:加油站](https://programmercarl.com/0134.加油站.html)中给出每一个加油站的汽油和开到这个加油站的消耗,问汽车能不能开一圈。 这道题目咋眼一看,感觉是一道模拟题,模拟一下汽车从每一个节点出发看看能不能开一圈,时间复杂度是O(n^2)。 @@ -28,7 +28,7 @@ ## 周二 -在[贪心算法:分发糖果](https://mp.weixin.qq.com/s/8MwlgFfvaNYmjGwjuMlETQ)中我们第一次接触了需要考虑两个维度的情况。 +在[贪心算法:分发糖果](https://programmercarl.com/0135.分发糖果.html)中我们第一次接触了需要考虑两个维度的情况。 例如这道题,是先考虑左边呢,还是考虑右边呢? @@ -54,7 +54,7 @@ ## 周三 -在[贪心算法:柠檬水找零](https://mp.weixin.qq.com/s/0kT4P-hzY7H6Ae0kjQqnZg)中我们模拟了买柠檬水找零的过程。 +在[贪心算法:柠檬水找零](https://programmercarl.com/0860.柠檬水找零.html)中我们模拟了买柠檬水找零的过程。 这道题目刚一看,可能会有点懵,这要怎么找零才能保证完整全部账单的找零呢? @@ -72,11 +72,11 @@ ## 周四 -在[贪心算法:根据身高重建队列](https://mp.weixin.qq.com/s/-2TgZVdOwS-DvtbjjDEbfw)中,我们再一次遇到了需要考虑两个维度的情况。 +在[贪心算法:根据身高重建队列](https://programmercarl.com/0406.根据身高重建队列.html)中,我们再一次遇到了需要考虑两个维度的情况。 -之前我们已经做过一道类似的了就是[贪心算法:分发糖果](https://mp.weixin.qq.com/s/8MwlgFfvaNYmjGwjuMlETQ),但本题比分发糖果难不少! +之前我们已经做过一道类似的了就是[贪心算法:分发糖果](https://programmercarl.com/0135.分发糖果.html),但本题比分发糖果难不少! -[贪心算法:根据身高重建队列](https://mp.weixin.qq.com/s/-2TgZVdOwS-DvtbjjDEbfw)中依然是要确定一边,然后在考虑另一边,两边一起考虑一定会蒙圈。 +[贪心算法:根据身高重建队列](https://programmercarl.com/0406.根据身高重建队列.html)中依然是要确定一边,然后在考虑另一边,两边一起考虑一定会蒙圈。 那么本题先确定k还是先确定h呢,也就是究竟先按h排序呢,还先按照k排序呢? @@ -92,7 +92,7 @@ 「代码随想录」里已经讲了十一道贪心题目了,大家可以发现在每一道题目的讲解中,我都是把什么是局部最优,和什么是全局最优说清楚。 -虽然有时候感觉贪心就是常识,但如果真正是常识性的题目,其实是模拟题,就不是贪心算法了!例如[贪心算法:加油站](https://mp.weixin.qq.com/s/aDbiNuEZIhy6YKgQXvKELw)中的贪心方法一,其实我就认为不是贪心算法,而是直接从全局最优的角度上来模拟,因为方法里没有体现局部最优的过程。 +虽然有时候感觉贪心就是常识,但如果真正是常识性的题目,其实是模拟题,就不是贪心算法了!例如[贪心算法:加油站](https://programmercarl.com/0134.加油站.html)中的贪心方法一,其实我就认为不是贪心算法,而是直接从全局最优的角度上来模拟,因为方法里没有体现局部最优的过程。 而且大家也会发现,贪心并没有想象中的那么简单,贪心往往妙的出其不意,触不及防!哈哈 diff --git a/problems/周总结/20201224贪心周末总结.md b/problems/周总结/20201224贪心周末总结.md index a82433cf..097ae9ed 100644 --- a/problems/周总结/20201224贪心周末总结.md +++ b/problems/周总结/20201224贪心周末总结.md @@ -4,7 +4,7 @@ ## 周一 -在[贪心算法:用最少数量的箭引爆气球](https://mp.weixin.qq.com/s/HxVAJ6INMfNKiGwI88-RFw)中,我们开始讲解了重叠区间问题,用最少的弓箭射爆所有气球,其本质就是找到最大的重叠区间。 +在[贪心算法:用最少数量的箭引爆气球](https://programmercarl.com/0452.用最少数量的箭引爆气球.html)中,我们开始讲解了重叠区间问题,用最少的弓箭射爆所有气球,其本质就是找到最大的重叠区间。 按照左边界经行排序后,如果气球重叠了,重叠气球中右边边界的最小值 之前的区间一定需要一个弓箭 @@ -16,7 +16,7 @@ ## 周二 -在[贪心算法:无重叠区间](https://mp.weixin.qq.com/s/oFOEoW-13Bm4mik-aqAOmw)中要去掉最少的区间,来让所有区间没有重叠。 +在[贪心算法:无重叠区间](https://programmercarl.com/0435.无重叠区间.html)中要去掉最少的区间,来让所有区间没有重叠。 我来按照右边界排序,从左向右记录非交叉区间的个数。最后用区间总数减去非交叉区间的个数就是需要移除的区间个数了。 @@ -24,11 +24,11 @@ ![435.无重叠区间](https://img-blog.csdnimg.cn/20201221201553618.png) -细心的同学就发现了,此题和 [贪心算法:用最少数量的箭引爆气球](https://mp.weixin.qq.com/s/HxVAJ6INMfNKiGwI88-RFw)非常像。 +细心的同学就发现了,此题和 [贪心算法:用最少数量的箭引爆气球](https://programmercarl.com/0452.用最少数量的箭引爆气球.html)非常像。 弓箭的数量就相当于是非交叉区间的数量,只要把弓箭那道题目代码里射爆气球的判断条件加个等号(认为[0,1][1,2]不是相邻区间),然后用总区间数减去弓箭数量 就是要移除的区间数量了。 -把[贪心算法:用最少数量的箭引爆气球](https://mp.weixin.qq.com/s/HxVAJ6INMfNKiGwI88-RFw)代码稍做修改,别可以AC本题。 +把[贪心算法:用最少数量的箭引爆气球](https://programmercarl.com/0452.用最少数量的箭引爆气球.html)代码稍做修改,别可以AC本题。 修改后的C++代码如下: ```CPP @@ -58,7 +58,7 @@ public: ## 周三 -[贪心算法:划分字母区间](https://mp.weixin.qq.com/s/pdX4JwV1AOpc_m90EcO2Hw)中我们要把这个字符串划分为尽可能多的片段,同一字母最多出现在一个片段中。 +[贪心算法:划分字母区间](https://programmercarl.com/0763.划分字母区间.html)中我们要把这个字符串划分为尽可能多的片段,同一字母最多出现在一个片段中。 这道题目leetcode上标的是贪心,其实我不认识是贪心,因为没感受到局部最优和全局最优的关系。 @@ -76,7 +76,7 @@ public: ## 周四 -[贪心算法:合并区间](https://mp.weixin.qq.com/s/royhzEM5tOkUFwUGrNStpw)中要合并所有重叠的区间。 +[贪心算法:合并区间](https://programmercarl.com/0056.合并区间.html)中要合并所有重叠的区间。 相信如果录友们前几天区间问题的题目认真练习了,今天题目就应该算简单一些了。 @@ -95,7 +95,7 @@ public: 其实很多区间的合并操作看起来都是常识,其实贪心算法有时候就是常识,哈哈,但也别小看了贪心算法。 -在[贪心算法:合并区间](https://mp.weixin.qq.com/s/royhzEM5tOkUFwUGrNStpw)中就说过,对于贪心算法,很多同学都是:「如果能凭常识直接做出来,就会感觉不到自己用了贪心, 一旦第一直觉想不出来, 可能就一直想不出来了」。 +在[贪心算法:合并区间](https://programmercarl.com/0056.合并区间.html)中就说过,对于贪心算法,很多同学都是:「如果能凭常识直接做出来,就会感觉不到自己用了贪心, 一旦第一直觉想不出来, 可能就一直想不出来了」。 所以还是要多看多做多练习! diff --git a/problems/周总结/20210107动规周末总结.md b/problems/周总结/20210107动规周末总结.md index 67957f05..b4baa4ad 100644 --- a/problems/周总结/20210107动规周末总结.md +++ b/problems/周总结/20210107动规周末总结.md @@ -3,7 +3,7 @@ ## 周一 -在[关于动态规划,你该了解这些!](https://mp.weixin.qq.com/s/ocZwfPlCWrJtVGACqFNAag)中我们讲解了动态规划的基础知识。 +在[关于动态规划,你该了解这些!](https://programmercarl.com/动态规划理论基础.html)中我们讲解了动态规划的基础知识。 首先讲一下动规和贪心的区别,其实大家不用太强调理论上的区别,做做题,就感受出来了。 @@ -33,13 +33,13 @@ ## 周二 -这道题目[动态规划:斐波那契数](https://mp.weixin.qq.com/s/ko0zLJplF7n_4TysnPOa_w)是当之无愧的动规入门题。 +这道题目[动态规划:斐波那契数](https://programmercarl.com/0509.斐波那契数.html)是当之无愧的动规入门题。 简单题,我们就是用来了解方法论的,用动规五部曲走一遍,题目其实已经把递推公式,和dp数组如何初始化都给我们了。 ## 周三 -[动态规划:爬楼梯](https://mp.weixin.qq.com/s/Ohop0jApSII9xxOMiFhGIw) 这道题目其实就是斐波那契数列。 +[动态规划:爬楼梯](https://programmercarl.com/0070.爬楼梯.html) 这道题目其实就是斐波那契数列。 但正常思考过程应该是推导完递推公式之后,发现这是斐波那契,而不是上来就知道这是斐波那契。 @@ -98,11 +98,11 @@ public: 这道绝佳的面试题我没有用过,如果录友们有面试别人的需求,就把这个套路拿去吧,哈哈哈。 -我在[通过一道面试题目,讲一讲递归算法的时间复杂度!](https://mp.weixin.qq.com/s/I6ZXFbw09NR31F5CJR_geQ)中,以我自己面试别人的真实经历,通过求x的n次方 这么简单的题目,就可以考察候选人对算法性能以及递归的理解深度,录友们可以看看,绝对有收获! +我在[通过一道面试题目,讲一讲递归算法的时间复杂度!](https://programmercarl.com/前序/通过一道面试题目,讲一讲递归算法的时间复杂度!.html)中,以我自己面试别人的真实经历,通过求x的n次方 这么简单的题目,就可以考察候选人对算法性能以及递归的理解深度,录友们可以看看,绝对有收获! ## 周四 -这道题目[动态规划:使用最小花费爬楼梯](https://mp.weixin.qq.com/s/djZB9gkyLFAKcQcSvKDorA)就是在爬台阶的基础上加了一个花费, +这道题目[动态规划:使用最小花费爬楼梯](https://programmercarl.com/0746.使用最小花费爬楼梯.html)就是在爬台阶的基础上加了一个花费, 这道题描述也确实有点魔幻。 diff --git a/problems/周总结/20210114动规周末总结.md b/problems/周总结/20210114动规周末总结.md index a49e0370..039f3596 100644 --- a/problems/周总结/20210114动规周末总结.md +++ b/problems/周总结/20210114动规周末总结.md @@ -1,7 +1,7 @@ ## 周一 -[动态规划:不同路径](https://mp.weixin.qq.com/s/MGgGIt4QCpFMROE9X9he_A)中求从出发点到终点有几种路径,只能向下或者向右移动一步。 +[动态规划:不同路径](https://programmercarl.com/0062.不同路径.html)中求从出发点到终点有几种路径,只能向下或者向右移动一步。 我们提供了三种方法,但重点讲解的还是动规,也是需要重点掌握的。 @@ -35,7 +35,7 @@ for (int i = 1; i < m; i++) { ## 周二 -[动态规划:不同路径还不够,要有障碍!](https://mp.weixin.qq.com/s/lhqF0O4le9-wvalptOVOww)相对于[动态规划:不同路径](https://mp.weixin.qq.com/s/MGgGIt4QCpFMROE9X9he_A)添加了障碍。 +[动态规划:不同路径还不够,要有障碍!](https://programmercarl.com/0063.不同路径II.html)相对于[动态规划:不同路径](https://programmercarl.com/0062.不同路径.html)添加了障碍。 dp[i][j]定义依然是:表示从(0 ,0)出发,到(i, j) 有dp[i][j]条不同的路径。 @@ -78,7 +78,7 @@ for (int i = 1; i < m; i++) { ## 周三 -[动态规划:整数拆分,你要怎么拆?](https://mp.weixin.qq.com/s/cVbyHrsWH_Rfzlj-ESr01A)给出一个整数,问有多少种拆分的方法。 +[动态规划:整数拆分,你要怎么拆?](https://programmercarl.com/0343.整数拆分.html)给出一个整数,问有多少种拆分的方法。 这道题目就有点难度了,题目中dp我也给出了两种方法,但通过两种方法的比较可以看出,对dp数组定义的理解,以及dp数组初始化的重要性。 @@ -121,7 +121,7 @@ for (int i = 3; i <= n ; i++) { **或者也可以理解j是拆分i的第一个整数**。 -[动态规划:整数拆分,你要怎么拆?](https://mp.weixin.qq.com/s/cVbyHrsWH_Rfzlj-ESr01A)总结里,我也给出了递推公式dp[i] = max(dp[i], dp[i - j] * dp[j])这种写法。 +[动态规划:整数拆分,你要怎么拆?](https://programmercarl.com/0343.整数拆分.html)总结里,我也给出了递推公式dp[i] = max(dp[i], dp[i - j] * dp[j])这种写法。 对于这种写法,一位录友总结的很好,意思就是:如果递推公式是dp[i-j] * dp[j],这样就相当于强制把一个数至少拆分成四份。 @@ -129,7 +129,7 @@ dp[i-j]至少是两个数的乘积,dp[j]又至少是两个数的乘积,但 ## 周四 -[动态规划:不同的二叉搜索树](https://mp.weixin.qq.com/s/8VE8pDrGxTf8NEVYBDwONw)给出n个不同的节点求能组成多少个不同二叉搜索树。 +[动态规划:不同的二叉搜索树](https://programmercarl.com/0096.不同的二叉搜索树.html)给出n个不同的节点求能组成多少个不同二叉搜索树。 这道题目还是比较难的,想到用动态规划的方法就很不容易了! @@ -145,7 +145,7 @@ n为5时候的dp数组状态如图: ## 总结 -本周题目已经开始点难度了,特别是[动态规划:不同的二叉搜索树](https://mp.weixin.qq.com/s/8VE8pDrGxTf8NEVYBDwONw)这道题目,明显感觉阅读量很低,可能是因为确实有点难吧。 +本周题目已经开始点难度了,特别是[动态规划:不同的二叉搜索树](https://programmercarl.com/0096.不同的二叉搜索树.html)这道题目,明显感觉阅读量很低,可能是因为确实有点难吧。 我现在也陷入了纠结,题目一简单,就会有录友和我反馈说题目太简单了,题目一难,阅读量就特别低。 diff --git a/problems/周总结/20210121动规周末总结.md b/problems/周总结/20210121动规周末总结.md index bffe47fb..e9427142 100644 --- a/problems/周总结/20210121动规周末总结.md +++ b/problems/周总结/20210121动规周末总结.md @@ -7,7 +7,7 @@ ## 周一 -[动态规划:关于01背包问题,你该了解这些!](https://mp.weixin.qq.com/s/FwIiPPmR18_AJO5eiidT6w)中,我们开始介绍了背包问题。 +[动态规划:关于01背包问题,你该了解这些!](https://programmercarl.com/背包理论基础01背包-1.html)中,我们开始介绍了背包问题。 首先对于背包的所有问题中,01背包是最最基础的,其他背包也是在01背包的基础上稍作变化。 @@ -75,7 +75,7 @@ for(int i = 1; i < weight.size(); i++) { // 遍历物品 ## 周二 -[动态规划:关于01背包问题,你该了解这些!(滚动数组)](https://mp.weixin.qq.com/s/M4uHxNVKRKm5HPjkNZBnFA)中把01背包的一维dp数组(滚动数组)实现详细讲解了一遍。 +[动态规划:关于01背包问题,你该了解这些!(滚动数组)](https://programmercarl.com/背包理论基础01背包-2.html)中把01背包的一维dp数组(滚动数组)实现详细讲解了一遍。 分析一下和二维dp数组有什么区别,在初始化和遍历顺序上又有什么差异? @@ -125,7 +125,7 @@ for(int i = 0; i < weight.size(); i++) { // 遍历物品 ## 周三 -[动态规划:416. 分割等和子集](https://mp.weixin.qq.com/s/sYw3QtPPQ5HMZCJcT4EaLQ)中我们开始用01背包来解决问题。 +[动态规划:416. 分割等和子集](https://programmercarl.com/0416.分割等和子集.html)中我们开始用01背包来解决问题。 只有确定了如下四点,才能把01背包问题套到本题上来。 @@ -138,11 +138,11 @@ for(int i = 0; i < weight.size(); i++) { // 遍历物品 ## 周四 -[动态规划:1049. 最后一块石头的重量 II](https://mp.weixin.qq.com/s/WbwAo3jaUaNJjvhHgq0BGg)这道题目其实和[动态规划:416. 分割等和子集](https://mp.weixin.qq.com/s/sYw3QtPPQ5HMZCJcT4EaLQ)是非常像的。 +[动态规划:1049. 最后一块石头的重量 II](https://programmercarl.com/1049.最后一块石头的重量II.html)这道题目其实和[动态规划:416. 分割等和子集](https://programmercarl.com/0416.分割等和子集.html)是非常像的。 本题其实就是尽量让石头分成重量相同的两堆,相撞之后剩下的石头最小,这样就化解成01背包问题了。 -[动态规划:416. 分割等和子集](https://mp.weixin.qq.com/s/sYw3QtPPQ5HMZCJcT4EaLQ)相当于是求背包是否正好装满,而本题是求背包最多能装多少。 +[动态规划:416. 分割等和子集](https://programmercarl.com/0416.分割等和子集.html)相当于是求背包是否正好装满,而本题是求背包最多能装多少。 这两道题目是对dp[target]的处理方式不同。这也考验的对dp[i]定义的理解。 diff --git a/problems/周总结/20210128动规周末总结.md b/problems/周总结/20210128动规周末总结.md index bea4cc60..06193a70 100644 --- a/problems/周总结/20210128动规周末总结.md +++ b/problems/周总结/20210128动规周末总结.md @@ -2,7 +2,7 @@ ## 周一 -[动态规划:目标和!](https://mp.weixin.qq.com/s/2pWmaohX75gwxvBENS-NCw)要求在数列之间加入+ 或者 -,使其和为S。 +[动态规划:目标和!](https://programmercarl.com/0494.目标和.html)要求在数列之间加入+ 或者 -,使其和为S。 所有数的总和为sum,假设加法的总和为x,那么可以推出x = (S + sum) / 2。 @@ -39,7 +39,7 @@ dp数组状态变化如下: ## 周二 -这道题目[动态规划:一和零!](https://mp.weixin.qq.com/s/x-u3Dsp76DlYqtCe0xEKJw)算有点难度。 +这道题目[动态规划:一和零!](https://programmercarl.com/0474.一和零.html)算有点难度。 **不少同学都以为是多重背包,其实这是一道标准的01背包**。 @@ -78,7 +78,7 @@ dp[i][j] = max(dp[i][j], dp[i - zeroNum][j - oneNum] + 1); 此时01背包我们就讲完了,正式开始完全背包。 -在[动态规划:关于完全背包,你该了解这些!](https://mp.weixin.qq.com/s/akwyxlJ4TLvKcw26KB9uJw)中我们讲解了完全背包的理论基础。 +在[动态规划:关于完全背包,你该了解这些!](https://programmercarl.com/背包问题理论基础完全背包.html)中我们讲解了完全背包的理论基础。 其实完全背包和01背包区别就是完全背包的物品是无限数量。 @@ -100,7 +100,7 @@ for(int i = 0; i < weight.size(); i++) { // 遍历物品 **那么为什么要先遍历物品,在遍历背包呢?** (灵魂拷问) -其实对于纯完全背包,先遍历物品,再遍历背包 与 先遍历背包,再遍历物品都是可以的。我在文中[动态规划:关于完全背包,你该了解这些!](https://mp.weixin.qq.com/s/akwyxlJ4TLvKcw26KB9uJw)也给出了详细的解释。 +其实对于纯完全背包,先遍历物品,再遍历背包 与 先遍历背包,再遍历物品都是可以的。我在文中[动态规划:关于完全背包,你该了解这些!](https://programmercarl.com/背包问题理论基础完全背包.html)也给出了详细的解释。 这个细节是很多同学忽略掉的点,其实也不算细节了,**相信不少同学在写背包的时候,两层for循环的先后循序搞不清楚,靠感觉来的**。 @@ -110,7 +110,7 @@ for(int i = 0; i < weight.size(); i++) { // 遍历物品 ## 周四 -在[动态规划:给你一些零钱,你要怎么凑?](https://mp.weixin.qq.com/s/PlowDsI4WMBOzf3q80AksQ)中就是给你一堆零钱(零钱个数无限),为凑成amount的组合数有几种。 +在[动态规划:给你一些零钱,你要怎么凑?](https://programmercarl.com/0518.零钱兑换II.html)中就是给你一堆零钱(零钱个数无限),为凑成amount的组合数有几种。 **注意这里组合数和排列数的区别!** @@ -134,7 +134,7 @@ for(int i = 0; i < weight.size(); i++) { // 遍历物品 其实这是一种错觉,或者说对动规理解的不够深入! -我在动规专题开篇介绍[关于动态规划,你该了解这些!](https://mp.weixin.qq.com/s/ocZwfPlCWrJtVGACqFNAag)中就强调了 **递推公式仅仅是 动规五部曲里的一小部分, dp数组的定义、初始化、遍历顺序,哪一点没有搞透的话,即使知道递推公式,遇到稍稍难一点的动规题目立刻会感觉写不出来了**。 +我在动规专题开篇介绍[关于动态规划,你该了解这些!](https://programmercarl.com/动态规划理论基础.html)中就强调了 **递推公式仅仅是 动规五部曲里的一小部分, dp数组的定义、初始化、遍历顺序,哪一点没有搞透的话,即使知道递推公式,遇到稍稍难一点的动规题目立刻会感觉写不出来了**。 此时相信大家对动规五部曲也有更深的理解了,同样也验证了Carl之前讲过的:**简单题是用来学习方法论的,而遇到难题才体现出方法论的重要性!** diff --git a/problems/周总结/20210204动规周末总结.md b/problems/周总结/20210204动规周末总结.md index d2417f8f..31009298 100644 --- a/problems/周总结/20210204动规周末总结.md +++ b/problems/周总结/20210204动规周末总结.md @@ -2,7 +2,7 @@ ## 周一 -[动态规划:377. 组合总和 Ⅳ](https://mp.weixin.qq.com/s/Iixw0nahJWQgbqVNk8k6gA)中给定一个由正整数组成且不存在重复数字的数组,找出和为给定目标正整数的组合的个数(顺序不同的序列被视作不同的组合)。 +[动态规划:377. 组合总和 Ⅳ](https://programmercarl.com/0377.组合总和Ⅳ.html)中给定一个由正整数组成且不存在重复数字的数组,找出和为给定目标正整数的组合的个数(顺序不同的序列被视作不同的组合)。 题目面试虽然是组合,但又强调顺序不同的序列被视作不同的组合,其实这道题目求的是排列数! @@ -10,7 +10,7 @@ 这个和前上周讲的组合问题又不一样,关键就体现在遍历顺序上! -在[动态规划:518.零钱兑换II](https://mp.weixin.qq.com/s/PlowDsI4WMBOzf3q80AksQ) 中就已经讲过了。 +在[动态规划:518.零钱兑换II](https://programmercarl.com/0518.零钱兑换II.html) 中就已经讲过了。 **如果求组合数就是外层for循环遍历物品,内层for遍历背包**。 @@ -40,7 +40,7 @@ public: ## 周二 -爬楼梯之前我们已经做过了,就是斐波那契数列,很好解,但[动态规划:70. 爬楼梯进阶版(完全背包)](https://mp.weixin.qq.com/s/e_wacnELo-2PG76EjrUakA)中我们进阶了一下。 +爬楼梯之前我们已经做过了,就是斐波那契数列,很好解,但[动态规划:70. 爬楼梯进阶版(完全背包)](https://programmercarl.com/0070.爬楼梯完全背包版本.html)中我们进阶了一下。 改为:每次可以爬 1 、 2、.....、m 个台阶。问有多少种不同的方法可以爬到楼顶呢? @@ -53,7 +53,7 @@ public: **此时大家应该发现这就是一个完全背包问题了!** -和昨天的题目[动态规划:377. 组合总和 Ⅳ](https://mp.weixin.qq.com/s/Iixw0nahJWQgbqVNk8k6gA)基本就是一道题了,遍历顺序也是一样一样的! +和昨天的题目[动态规划:377. 组合总和 Ⅳ](https://programmercarl.com/0377.组合总和Ⅳ.html)基本就是一道题了,遍历顺序也是一样一样的! 代码如下: ```CPP @@ -77,7 +77,7 @@ public: ## 周三 -[动态规划:322.零钱兑换](https://mp.weixin.qq.com/s/dyk-xNilHzNtVdPPLObSeQ)给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数(每种硬币的数量是无限的)。 +[动态规划:322.零钱兑换](https://programmercarl.com/0322.零钱兑换.html)给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数(每种硬币的数量是无限的)。 这里我们都知道这是完全背包。 @@ -137,10 +137,10 @@ public: ## 周四 -[动态规划:279.完全平方数](https://mp.weixin.qq.com/s/VfJT78p7UGpDZsapKF_QJQ)给定正整数 n,找到若干个完全平方数(比如 1, 4, 9, 16, ...)使得它们的和等于 n。你需要让组成和的完全平方数的个数最少(平方数可以重复使用)。 +[动态规划:279.完全平方数](https://programmercarl.com/0279.完全平方数.html)给定正整数 n,找到若干个完全平方数(比如 1, 4, 9, 16, ...)使得它们的和等于 n。你需要让组成和的完全平方数的个数最少(平方数可以重复使用)。 -如果按顺序把前面的文章都看了,这道题目就是简单题了。 dp[i]的定义,递推公式,初始化,遍历顺序,都是和[动态规划:322. 零钱兑换](https://mp.weixin.qq.com/s/dyk-xNilHzNtVdPPLObSeQ) 一样一样的。 +如果按顺序把前面的文章都看了,这道题目就是简单题了。 dp[i]的定义,递推公式,初始化,遍历顺序,都是和[动态规划:322. 零钱兑换](https://programmercarl.com/0322.零钱兑换.html) 一样一样的。 要是没有前面的基础上来做这道题,那这道题目就有点难度了。 @@ -193,9 +193,9 @@ public: 我这里做一下总结: -求组合数:[动态规划:518.零钱兑换II](https://mp.weixin.qq.com/s/PlowDsI4WMBOzf3q80AksQ) -求排列数:[动态规划:377. 组合总和 Ⅳ](https://mp.weixin.qq.com/s/Iixw0nahJWQgbqVNk8k6gA)、[动态规划:70. 爬楼梯进阶版(完全背包)](https://mp.weixin.qq.com/s/e_wacnELo-2PG76EjrUakA) -求最小数:[动态规划:322. 零钱兑换](https://mp.weixin.qq.com/s/dyk-xNilHzNtVdPPLObSeQ)、[动态规划:279.完全平方数](https://mp.weixin.qq.com/s/VfJT78p7UGpDZsapKF_QJQ) +求组合数:[动态规划:518.零钱兑换II](https://programmercarl.com/0518.零钱兑换II.html) +求排列数:[动态规划:377. 组合总和 Ⅳ](https://programmercarl.com/0377.组合总和Ⅳ.html)、[动态规划:70. 爬楼梯进阶版(完全背包)](https://programmercarl.com/0070.爬楼梯完全背包版本.html) +求最小数:[动态规划:322. 零钱兑换](https://programmercarl.com/0322.零钱兑换.html)、[动态规划:279.完全平方数](https://programmercarl.com/0279.完全平方数.html) 此时我们就已经把完全背包的遍历顺序研究的透透的了! diff --git a/problems/周总结/20210225动规周末总结.md b/problems/周总结/20210225动规周末总结.md index ea3c5515..ae8b4800 100644 --- a/problems/周总结/20210225动规周末总结.md +++ b/problems/周总结/20210225动规周末总结.md @@ -3,7 +3,7 @@ ## 周一 -[动态规划:开始打家劫舍!](https://mp.weixin.qq.com/s/UZ31WdLEEFmBegdgLkJ8Dw)中就是给一个数组相邻之间不能连着偷,如果偷才能得到最大金钱。 +[动态规划:开始打家劫舍!](https://programmercarl.com/0198.打家劫舍.html)中就是给一个数组相邻之间不能连着偷,如果偷才能得到最大金钱。 1. 确定dp数组含义 @@ -35,7 +35,7 @@ dp[1] = max(nums[0], nums[1]); ## 周二 -[动态规划:继续打家劫舍!](https://mp.weixin.qq.com/s/kKPx4HpH3RArbRcxAVHbeQ)就是数组成环了,然后相邻的不能连着偷。 +[动态规划:继续打家劫舍!](https://programmercarl.com/0213.打家劫舍II.html)就是数组成环了,然后相邻的不能连着偷。 这里主要考虑清楚三种情况: @@ -61,11 +61,11 @@ dp[1] = max(nums[0], nums[1]); 所以我在本文重点强调了情况一二三是“考虑”的范围,而具体房间偷与不偷交给递推公式去抉择。 -剩下的就和[动态规划:开始打家劫舍!](https://mp.weixin.qq.com/s/UZ31WdLEEFmBegdgLkJ8Dw)是一个逻辑了。 +剩下的就和[动态规划:开始打家劫舍!](https://programmercarl.com/0198.打家劫舍.html)是一个逻辑了。 ## 周三 -[动态规划:还要打家劫舍!](https://mp.weixin.qq.com/s/BOJ1lHsxbQxUZffXlgglEQ)这次是在一颗二叉树上打家劫舍了,条件还是一样的,相临的不能偷。 +[动态规划:还要打家劫舍!](https://programmercarl.com/0337.打家劫舍III.html)这次是在一颗二叉树上打家劫舍了,条件还是一样的,相临的不能偷。 这道题目是树形DP的入门题目,其实树形DP其实就是在树上进行递推公式的推导,没有什么神秘的。 @@ -184,14 +184,14 @@ return {val2, val1}; 因为平时我们习惯了在一维数组或者二维数组上推导公式,一下子换成了树,就需要对树的遍历方式足够了解! -大家还记不记得我在讲解贪心专题的时候,讲到这道题目:[贪心算法:我要监控二叉树!](https://mp.weixin.qq.com/s/kCxlLLjWKaE6nifHC3UL2Q),这也是贪心算法在树上的应用。**那我也可以把这个算法起一个名字,叫做树形贪心**,哈哈哈 +大家还记不记得我在讲解贪心专题的时候,讲到这道题目:[贪心算法:我要监控二叉树!](https://programmercarl.com/0968.监控二叉树.html),这也是贪心算法在树上的应用。**那我也可以把这个算法起一个名字,叫做树形贪心**,哈哈哈 “树形贪心”词汇从此诞生,来自「代码随想录」 ## 周四 -[动态规划:买卖股票的最佳时机](https://mp.weixin.qq.com/s/keWo5qYJY4zmHn3amfXdfQ) 一段时间,只能买买一次,问最大收益。 +[动态规划:买卖股票的最佳时机](https://programmercarl.com/0121.买卖股票的最佳时机.html) 一段时间,只能买买一次,问最大收益。 这里我给出了三中解法: diff --git a/problems/周总结/20210304动规周末总结.md b/problems/周总结/20210304动规周末总结.md index 9fea6244..dad9884d 100644 --- a/problems/周总结/20210304动规周末总结.md +++ b/problems/周总结/20210304动规周末总结.md @@ -3,9 +3,9 @@ ## 周一 -[动态规划:买卖股票的最佳时机II](https://mp.weixin.qq.com/s/d4TRWFuhaY83HPa6t5ZL-w)中股票可以买买多了次! +[动态规划:买卖股票的最佳时机II](https://programmercarl.com/0122.买卖股票的最佳时机II(动态规划).html)中股票可以买买多了次! -这也是和[121. 买卖股票的最佳时机](https://mp.weixin.qq.com/s/keWo5qYJY4zmHn3amfXdfQ)的唯一区别(注意只有一只股票,所以再次购买前要出售掉之前的股票) +这也是和[121. 买卖股票的最佳时机](https://programmercarl.com/0121.买卖股票的最佳时机.html)的唯一区别(注意只有一只股票,所以再次购买前要出售掉之前的股票) 重点在于递推公式公式的不同。 @@ -22,7 +22,7 @@ dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] - prices[i]); dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] + prices[i]); ``` -大家可以发现本题和[121. 买卖股票的最佳时机](https://mp.weixin.qq.com/s/keWo5qYJY4zmHn3amfXdfQ)的代码几乎一样,唯一的区别在: +大家可以发现本题和[121. 买卖股票的最佳时机](https://programmercarl.com/0121.买卖股票的最佳时机.html)的代码几乎一样,唯一的区别在: ``` dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] - prices[i]); @@ -32,7 +32,7 @@ dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] - prices[i]); ## 周二 -[动态规划:买卖股票的最佳时机III](https://mp.weixin.qq.com/s/Sbs157mlVDtAR0gbLpdKzg)中最多只能完成两笔交易。 +[动态规划:买卖股票的最佳时机III](https://programmercarl.com/0123.买卖股票的最佳时机III.html)中最多只能完成两笔交易。 **这意味着可以买卖一次,可以买卖两次,也可以不买卖**。 @@ -85,9 +85,9 @@ dp[0][4] = 0; ## 周三 -[动态规划:买卖股票的最佳时机IV](https://mp.weixin.qq.com/s/jtxZJWAo2y5sUsW647Z5cw)最多可以完成 k 笔交易。 +[动态规划:买卖股票的最佳时机IV](https://programmercarl.com/0188.买卖股票的最佳时机IV.html)最多可以完成 k 笔交易。 -相对于上一道[动态规划:123.买卖股票的最佳时机III](https://mp.weixin.qq.com/s/Sbs157mlVDtAR0gbLpdKzg),本题需要通过前两次的交易,来类比前k次的交易 +相对于上一道[动态规划:123.买卖股票的最佳时机III](https://programmercarl.com/0123.买卖股票的最佳时机III.html),本题需要通过前两次的交易,来类比前k次的交易 1. 确定dp数组以及下标的含义 @@ -117,7 +117,7 @@ for (int j = 0; j < 2 * k - 1; j += 2) { } ``` -**本题和[动态规划:123.买卖股票的最佳时机III](https://mp.weixin.qq.com/s/Sbs157mlVDtAR0gbLpdKzg)最大的区别就是这里要类比j为奇数是买,偶数是卖剩的状态**。 +**本题和[动态规划:123.买卖股票的最佳时机III](https://programmercarl.com/0123.买卖股票的最佳时机III.html)最大的区别就是这里要类比j为奇数是买,偶数是卖剩的状态**。 3. dp数组如何初始化 @@ -147,9 +147,9 @@ for (int j = 1; j < 2 * k; j += 2) { ## 周四 -[动态规划:最佳买卖股票时机含冷冻期](https://mp.weixin.qq.com/s/IgC0iWWCDpYL9ZbTHGHgfw)尽可能地完成更多的交易(多次买卖一支股票),但有冷冻期,冷冻期为1天 +[动态规划:最佳买卖股票时机含冷冻期](https://programmercarl.com/0309.最佳买卖股票时机含冷冻期.html)尽可能地完成更多的交易(多次买卖一支股票),但有冷冻期,冷冻期为1天 -相对于[动态规划:122.买卖股票的最佳时机II](https://mp.weixin.qq.com/s/d4TRWFuhaY83HPa6t5ZL-w),本题加上了一个冷冻期 +相对于[动态规划:122.买卖股票的最佳时机II](https://programmercarl.com/0122.买卖股票的最佳时机II(动态规划).html),本题加上了一个冷冻期 **本题则需要第三个状态:不持有股票(冷冻期)的最多现金**。 diff --git a/problems/周总结/二叉树阶段总结系列一.md b/problems/周总结/二叉树阶段总结系列一.md index c8235ff1..595f367d 100644 --- a/problems/周总结/二叉树阶段总结系列一.md +++ b/problems/周总结/二叉树阶段总结系列一.md @@ -4,15 +4,15 @@ **注意这个周末总结和系列总结还是不一样的(二叉树还远没有结束),这个总结是针对留言疑问以及刷题群里讨论内容的归纳。** -1. [关于二叉树,你该了解这些!](https://mp.weixin.qq.com/s/q_eKfL8vmSbSFcptZ3aeRA) -2. [二叉树:一入递归深似海,从此offer是路人](https://mp.weixin.qq.com/s/Ww60X5mIKWdMQV4cN3ejOA) -3. [二叉树:听说递归能做的,栈也能做!](https://mp.weixin.qq.com/s/OH7aCVJ5-Gi32PkNCoZk4A) -4. [二叉树:前中后序迭代方式的写法就不能统一一下么?](https://mp.weixin.qq.com/s/ATQMPCpBlaAgrqdLDMVPZA) -5. [二叉树:层序遍历登场!](https://mp.weixin.qq.com/s/4-bDKi7SdwfBGRm9FYduiA) -6. [二叉树:你真的会翻转二叉树么?](https://mp.weixin.qq.com/s/jG0MgYR9DoUMYcRRF7magw) +1. [关于二叉树,你该了解这些!](https://programmercarl.com/二叉树理论基础.html) +2. [二叉树:一入递归深似海,从此offer是路人](https://programmercarl.com/二叉树的递归遍历.html) +3. [二叉树:听说递归能做的,栈也能做!](https://programmercarl.com/二叉树的迭代遍历.html) +4. [二叉树:前中后序迭代方式的写法就不能统一一下么?](https://programmercarl.com/二叉树的统一迭代法.html) +5. [二叉树:层序遍历登场!](https://programmercarl.com/0102.二叉树的层序遍历.html) +6. [二叉树:你真的会翻转二叉树么?](https://programmercarl.com/0226.翻转二叉树.html) -## [关于二叉树,你该了解这些!](https://mp.weixin.qq.com/s/q_eKfL8vmSbSFcptZ3aeRA) +## [关于二叉树,你该了解这些!](https://programmercarl.com/二叉树理论基础.html) 有同学会把红黑树和二叉平衡搜索树弄分开了,其实红黑树就是一种二叉平衡搜索树,这两个树不是独立的,所以C++中map、multimap、set、multiset的底层实现机制是二叉平衡搜索树,再具体一点是红黑树。 @@ -51,18 +51,18 @@ a->right = NULL; morris遍历是二叉树遍历算法的超强进阶算法,morris遍历可以将非递归遍历中的空间复杂度降为O(1),感兴趣大家就去查一查学习学习,比较小众,面试几乎不会考。我其实也没有研究过,就不做过多介绍了。 -## [二叉树的递归遍历](https://mp.weixin.qq.com/s/Ww60X5mIKWdMQV4cN3ejOA) +## [二叉树的递归遍历](https://programmercarl.com/二叉树的递归遍历.html) -在[二叉树:一入递归深似海,从此offer是路人](https://mp.weixin.qq.com/s/Ww60X5mIKWdMQV4cN3ejOA)中讲到了递归三要素,以及前中后序的递归写法。 +在[二叉树:一入递归深似海,从此offer是路人](https://programmercarl.com/二叉树的递归遍历.html)中讲到了递归三要素,以及前中后序的递归写法。 -文章中我给出了leetcode上三道二叉树的前中后序题目,但是看完[二叉树:一入递归深似海,从此offer是路人](https://mp.weixin.qq.com/s/Ww60X5mIKWdMQV4cN3ejOA),依然可以解决n叉树的前后序遍历,在leetcode上分别是 +文章中我给出了leetcode上三道二叉树的前中后序题目,但是看完[二叉树:一入递归深似海,从此offer是路人](https://programmercarl.com/二叉树的递归遍历.html),依然可以解决n叉树的前后序遍历,在leetcode上分别是 * 589. N叉树的前序遍历 * 590. N叉树的后序遍历 大家可以再去把这两道题目做了。 -## [二叉树的非递归遍历](https://mp.weixin.qq.com/s/OH7aCVJ5-Gi32PkNCoZk4A) +## [二叉树的非递归遍历](https://programmercarl.com/二叉树的迭代遍历.html) 细心的同学发现文中前后序遍历空节点是入栈的,其实空节点入不入栈都差不多,但感觉空节点不入栈确实清晰一些,符合文中动画的演示。 @@ -125,7 +125,7 @@ public: ## 周四 -在[二叉树:前中后序迭代方式的写法就不能统一一下么?](https://mp.weixin.qq.com/s/WKg0Ty1_3SZkztpHubZPRg)中我们使用空节点作为标记,给出了统一的前中后序迭代法。 +在[二叉树:前中后序迭代方式的写法就不能统一一下么?](https://programmercarl.com/二叉树的统一迭代法.html)中我们使用空节点作为标记,给出了统一的前中后序迭代法。 此时又多了一种前中后序的迭代写法,那么有同学问了:前中后序迭代法是不是一定要统一来写,这样才算是规范。 @@ -135,7 +135,7 @@ public: ## 周五 -在[二叉树:层序遍历登场!](https://mp.weixin.qq.com/s/Gb3BjakIKGNpup2jYtTzog)中我们介绍了二叉树的另一种遍历方式(图论中广度优先搜索在二叉树上的应用)即:层序遍历。 +在[二叉树:层序遍历登场!](https://programmercarl.com/0102.二叉树的层序遍历.html)中我们介绍了二叉树的另一种遍历方式(图论中广度优先搜索在二叉树上的应用)即:层序遍历。 看完这篇文章,去leetcode上怒刷五题,文章中 编号107题目的样例图放错了(原谅我匆忙之间总是手抖),但不影响大家理解。 @@ -145,7 +145,7 @@ public: ## 周六 -在[二叉树:你真的会翻转二叉树么?](https://mp.weixin.qq.com/s/6gY1MiXrnm-khAAJiIb5Bg)中我们把翻转二叉树这么一道简单又经典的问题,充分的剖析了一波,相信就算做过这道题目的同学,看完本篇之后依然有所收获! +在[二叉树:你真的会翻转二叉树么?](https://programmercarl.com/0226.翻转二叉树.html)中我们把翻转二叉树这么一道简单又经典的问题,充分的剖析了一波,相信就算做过这道题目的同学,看完本篇之后依然有所收获! **文中我指的是递归的中序遍历是不行的,因为使用递归的中序遍历,某些节点的左右孩子会翻转两次。** diff --git a/problems/哈希表总结.md b/problems/哈希表总结.md index 28865920..58e386bc 100644 --- a/problems/哈希表总结.md +++ b/problems/哈希表总结.md @@ -12,7 +12,7 @@ # 哈希表理论基础 -在[关于哈希表,你该了解这些!](https://mp.weixin.qq.com/s/RSUANESA_tkhKhYe3ZR8Jg)中,我们介绍了哈希表的基础理论知识,不同于枯燥的讲解,这里介绍了都是对刷题有帮助的理论知识点。 +在[关于哈希表,你该了解这些!](https://programmercarl.com/哈希表理论基础.html)中,我们介绍了哈希表的基础理论知识,不同于枯燥的讲解,这里介绍了都是对刷题有帮助的理论知识点。 **一般来说哈希表都是用来快速判断一个元素是否出现集合里**。 @@ -28,7 +28,7 @@ * set(集合) * map(映射) -在C++语言中,set 和 map 都分别提供了三种数据结构,每种数据结构的底层实现和用途都有所不同,在[关于哈希表,你该了解这些!](https://mp.weixin.qq.com/s/RSUANESA_tkhKhYe3ZR8Jg)中我给出了详细分析,这一知识点很重要! +在C++语言中,set 和 map 都分别提供了三种数据结构,每种数据结构的底层实现和用途都有所不同,在[关于哈希表,你该了解这些!](https://programmercarl.com/哈希表理论基础.html)中我给出了详细分析,这一知识点很重要! 例如什么时候用std::set,什么时候用std::multiset,什么时候用std::unordered_set,都是很有考究的。 @@ -40,13 +40,13 @@ 一些应用场景就是为数组量身定做的。 -在[242.有效的字母异位词](https://mp.weixin.qq.com/s/ffS8jaVFNUWyfn_8T31IdA)中,我们提到了数组就是简单的哈希表,但是数组的大小是受限的! +在[242.有效的字母异位词](https://programmercarl.com/0242.有效的字母异位词.html)中,我们提到了数组就是简单的哈希表,但是数组的大小是受限的! 这道题目包含小写字母,那么使用数组来做哈希最合适不过。 -在[383.赎金信](https://mp.weixin.qq.com/s/qAXqv--UERmiJNNpuphOUQ)中同样要求只有小写字母,那么就给我们浓浓的暗示,用数组! +在[383.赎金信](https://programmercarl.com/0383.赎金信.html)中同样要求只有小写字母,那么就给我们浓浓的暗示,用数组! -本题和[242.有效的字母异位词](https://mp.weixin.qq.com/s/ffS8jaVFNUWyfn_8T31IdA)很像,[242.有效的字母异位词](https://mp.weixin.qq.com/s/ffS8jaVFNUWyfn_8T31IdA)是求 字符串a 和 字符串b 是否可以相互组成,在[383.赎金信](https://mp.weixin.qq.com/s/qAXqv--UERmiJNNpuphOUQ)中是求字符串a能否组成字符串b,而不用管字符串b 能不能组成字符串a。 +本题和[242.有效的字母异位词](https://programmercarl.com/0242.有效的字母异位词.html)很像,[242.有效的字母异位词](https://programmercarl.com/0242.有效的字母异位词.html)是求 字符串a 和 字符串b 是否可以相互组成,在[383.赎金信](https://programmercarl.com/0383.赎金信.html)中是求字符串a能否组成字符串b,而不用管字符串b 能不能组成字符串a。 一些同学可能想,用数组干啥,都用map不就完事了。 @@ -55,7 +55,7 @@ ## set作为哈希表 -在[349. 两个数组的交集](https://mp.weixin.qq.com/s/aMSA5zrp3jJcLjuSB0Es2Q)中我们给出了什么时候用数组就不行了,需要用set。 +在[349. 两个数组的交集](https://programmercarl.com/0349.两个数组的交集.html)中我们给出了什么时候用数组就不行了,需要用set。 这道题目没有限制数值的大小,就无法使用数组来做哈希表了。 @@ -66,7 +66,7 @@ 所以此时一样的做映射的话,就可以使用set了。 -关于set,C++ 给提供了如下三种可用的数据结构:(详情请看[关于哈希表,你该了解这些!](https://mp.weixin.qq.com/s/RSUANESA_tkhKhYe3ZR8Jg)) +关于set,C++ 给提供了如下三种可用的数据结构:(详情请看[关于哈希表,你该了解这些!](https://programmercarl.com/哈希表理论基础.html)) * std::set * std::multiset @@ -74,12 +74,12 @@ std::set和std::multiset底层实现都是红黑树,std::unordered_set的底层实现是哈希, 使用unordered_set 读写效率是最高的,本题并不需要对数据进行排序,而且还不要让数据重复,所以选择unordered_set。 -在[202.快乐数](https://mp.weixin.qq.com/s/n5q0ujxxrjQS3xuh3dgqBQ)中,我们再次使用了unordered_set来判断一个数是否重复出现过。 +在[202.快乐数](https://programmercarl.com/0202.快乐数.html)中,我们再次使用了unordered_set来判断一个数是否重复出现过。 ## map作为哈希表 -在[1.两数之和](https://mp.weixin.qq.com/s/vaMsLnH-f7_9nEK4Cuu3KQ)中map正式登场。 +在[1.两数之和](https://programmercarl.com/0001.两数之和.html)中map正式登场。 来说一说:使用数组和set来做哈希法的局限。 @@ -88,7 +88,7 @@ std::set和std::multiset底层实现都是红黑树,std::unordered_set的底 map是一种``的结构,本题可以用key保存数值,用value在保存数值所在的下表。所以使用map最为合适。 -C++提供如下三种map::(详情请看[关于哈希表,你该了解这些!](https://mp.weixin.qq.com/s/RSUANESA_tkhKhYe3ZR8Jg)) +C++提供如下三种map::(详情请看[关于哈希表,你该了解这些!](https://programmercarl.com/哈希表理论基础.html)) * std::map * std::multimap @@ -96,19 +96,19 @@ C++提供如下三种map::(详情请看[关于哈希表,你该了解这 std::unordered_map 底层实现为哈希,std::map 和std::multimap 的底层实现是红黑树。 -同理,std::map 和std::multimap 的key也是有序的(这个问题也经常作为面试题,考察对语言容器底层的理解),[1.两数之和](https://mp.weixin.qq.com/s/vaMsLnH-f7_9nEK4Cuu3KQ)中并不需要key有序,选择std::unordered_map 效率更高! +同理,std::map 和std::multimap 的key也是有序的(这个问题也经常作为面试题,考察对语言容器底层的理解),[1.两数之和](https://programmercarl.com/0001.两数之和.html)中并不需要key有序,选择std::unordered_map 效率更高! -在[454.四数相加](https://mp.weixin.qq.com/s/12g_w6RzHuEpFts1pT6BWw)中我们提到了其实需要哈希的地方都能找到map的身影。 +在[454.四数相加](https://programmercarl.com/0454.四数相加II.html)中我们提到了其实需要哈希的地方都能找到map的身影。 -本题咋眼一看好像和[18. 四数之和](https://mp.weixin.qq.com/s/SBU3THi1Kv6Sar7htqCB2Q),[15.三数之和](https://mp.weixin.qq.com/s/QfTNEByq1YlNSXRKEumwHg)差不多,其实差很多! +本题咋眼一看好像和[18. 四数之和](https://programmercarl.com/0018.四数之和.html),[15.三数之和](https://programmercarl.com/0015.三数之和.html)差不多,其实差很多! -**关键差别是本题为四个独立的数组,只要找到A[i] + B[j] + C[k] + D[l] = 0就可以,不用考虑重复问题,而[18. 四数之和](https://mp.weixin.qq.com/s/SBU3THi1Kv6Sar7htqCB2Q),[15.三数之和](https://mp.weixin.qq.com/s/QfTNEByq1YlNSXRKEumwHg)是一个数组(集合)里找到和为0的组合,可就难很多了!** +**关键差别是本题为四个独立的数组,只要找到A[i] + B[j] + C[k] + D[l] = 0就可以,不用考虑重复问题,而[18. 四数之和](https://programmercarl.com/0018.四数之和.html),[15.三数之和](https://programmercarl.com/0015.三数之和.html)是一个数组(集合)里找到和为0的组合,可就难很多了!** 用哈希法解决了两数之和,很多同学会感觉用哈希法也可以解决三数之和,四数之和。 其实是可以解决,但是非常麻烦,需要去重导致代码效率很低。 -在[15.三数之和](https://mp.weixin.qq.com/s/QfTNEByq1YlNSXRKEumwHg)中我给出了哈希法和双指针两个解法,大家就可以体会到,使用哈希法还是比较麻烦的。 +在[15.三数之和](https://programmercarl.com/0015.三数之和.html)中我给出了哈希法和双指针两个解法,大家就可以体会到,使用哈希法还是比较麻烦的。 所以18. 四数之和,15.三数之和都推荐使用双指针法! diff --git a/problems/回溯总结.md b/problems/回溯总结.md index 474db74a..f4578c83 100644 --- a/problems/回溯总结.md +++ b/problems/回溯总结.md @@ -14,7 +14,7 @@ 关于回溯算法理论基础,我录了一期B站视频[带你学透回溯算法(理论篇)](https://www.bilibili.com/video/BV1cy4y167mM)如果对回溯算法还不了解的话,可以看一下。 -在[关于回溯算法,你该了解这些!](https://mp.weixin.qq.com/s/gjSgJbNbd1eAA5WkA-HeWw)中我们详细的介绍了回溯算法的理论知识,不同于教科书般的讲解,这里介绍的回溯法的效率,解决的问题以及模板都是在刷题的过程中非常实用! +在[关于回溯算法,你该了解这些!](https://programmercarl.com/回溯算法理论基础.html)中我们详细的介绍了回溯算法的理论知识,不同于教科书般的讲解,这里介绍的回溯法的效率,解决的问题以及模板都是在刷题的过程中非常实用! **回溯是递归的副产品,只要有递归就会有回溯**,所以回溯法也经常和二叉树遍历,深度优先搜索混在一起,因为这两种方式都是用了递归。 @@ -32,7 +32,7 @@ 回溯法确实不好理解,所以需要把回溯法抽象为一个图形来理解就容易多了,**在后面的每一道回溯法的题目我都将遍历过程抽象为树形结构方便大家的理解**。 -在[关于回溯算法,你该了解这些!](https://mp.weixin.qq.com/s/gjSgJbNbd1eAA5WkA-HeWw)还用了回溯三部曲来分析回溯算法,并给出了回溯法的模板: +在[关于回溯算法,你该了解这些!](https://programmercarl.com/回溯算法理论基础.html)还用了回溯三部曲来分析回溯算法,并给出了回溯法的模板: ``` void backtracking(参数) { @@ -55,7 +55,7 @@ void backtracking(参数) { ## 组合问题 -在[回溯算法:求组合问题!](https://mp.weixin.qq.com/s/OnBjbLzuipWz_u4QfmgcqQ)中,我们开始用回溯法解决第一道题目:组合问题。 +在[回溯算法:求组合问题!](https://programmercarl.com/0077.组合.html)中,我们开始用回溯法解决第一道题目:组合问题。 我在文中开始的时候给大家列举k层for循环例子,进而得出都是同样是暴利解法,为什么要用回溯法! @@ -71,13 +71,13 @@ void backtracking(参数) { **所以,录友们刚开始学回溯法,起跑姿势就很标准了!** -优化回溯算法只有剪枝一种方法,在[回溯算法:组合问题再剪剪枝](https://mp.weixin.qq.com/s/Ri7spcJMUmph4c6XjPWXQA)中把回溯法代码做了剪枝优化,树形结构如图: +优化回溯算法只有剪枝一种方法,在[回溯算法:组合问题再剪剪枝](https://programmercarl.com/0077.组合优化.html)中把回溯法代码做了剪枝优化,树形结构如图: ![77.组合4](https://img-blog.csdnimg.cn/20201118153133458.png) 大家可以一目了然剪的究竟是哪里。 -**[回溯算法:求组合问题!](https://mp.weixin.qq.com/s/OnBjbLzuipWz_u4QfmgcqQ)剪枝精髓是:for循环在寻找起点的时候要有一个范围,如果这个起点到集合终止之间的元素已经不够题目要求的k个元素了,就没有必要搜索了**。 +**[回溯算法:求组合问题!](https://programmercarl.com/0077.组合.html)剪枝精髓是:for循环在寻找起点的时候要有一个范围,如果这个起点到集合终止之间的元素已经不够题目要求的k个元素了,就没有必要搜索了**。 **在for循环上做剪枝操作是回溯法剪枝的常见套路!** 后面的题目还会经常用到。 @@ -86,7 +86,7 @@ void backtracking(参数) { ### 组合总和(一) -在[回溯算法:求组合总和!](https://mp.weixin.qq.com/s/HX7WW6ixbFZJASkRnCTC3w)中,相当于 [回溯算法:求组合问题!](https://mp.weixin.qq.com/s/OnBjbLzuipWz_u4QfmgcqQ)加了一个元素总和的限制。 +在[回溯算法:求组合总和!](https://programmercarl.com/0216.组合总和III.html)中,相当于 [回溯算法:求组合问题!](https://programmercarl.com/0077.组合.html)加了一个元素总和的限制。 树形结构如图: ![216.组合总和III](https://img-blog.csdnimg.cn/20201118201921245.png) @@ -95,21 +95,21 @@ void backtracking(参数) { ![216.组合总和III1](https://img-blog.csdnimg.cn/20201118202038240.png) -在本题中,依然还可以有一个剪枝,就是[回溯算法:组合问题再剪剪枝](https://mp.weixin.qq.com/s/Ri7spcJMUmph4c6XjPWXQA)中提到的,对for循环选择的起始范围的剪枝。 +在本题中,依然还可以有一个剪枝,就是[回溯算法:组合问题再剪剪枝](https://programmercarl.com/0077.组合优化.html)中提到的,对for循环选择的起始范围的剪枝。 所以剪枝的代码可以在for循环加上 `i <= 9 - (k - path.size()) + 1` 的限制! ### 组合总和(二) -在[回溯算法:求组合总和(二)](https://mp.weixin.qq.com/s/FLg8G6EjVcxBjwCbzpACPw)中讲解的组合总和问题,和[回溯算法:求组合问题!](https://mp.weixin.qq.com/s/OnBjbLzuipWz_u4QfmgcqQ),[回溯算法:求组合总和!](https://mp.weixin.qq.com/s/HX7WW6ixbFZJASkRnCTC3w)和区别是:本题没有数量要求,可以无限重复,但是有总和的限制,所以间接的也是有个数的限制。 +在[回溯算法:求组合总和(二)](https://programmercarl.com/0039.组合总和.html)中讲解的组合总和问题,和[回溯算法:求组合问题!](https://programmercarl.com/0077.组合.html),[回溯算法:求组合总和!](https://programmercarl.com/0216.组合总和III.html)和区别是:本题没有数量要求,可以无限重复,但是有总和的限制,所以间接的也是有个数的限制。 不少同学都是看到可以重复选择,就义无反顾的把startIndex去掉了。 **本题还需要startIndex来控制for循环的起始位置,对于组合问题,什么时候需要startIndex呢?** -我举过例子,如果是一个集合来求组合的话,就需要startIndex,例如:[回溯算法:求组合问题!](https://mp.weixin.qq.com/s/OnBjbLzuipWz_u4QfmgcqQ),[回溯算法:求组合总和!](https://mp.weixin.qq.com/s/HX7WW6ixbFZJASkRnCTC3w)。 +我举过例子,如果是一个集合来求组合的话,就需要startIndex,例如:[回溯算法:求组合问题!](https://programmercarl.com/0077.组合.html),[回溯算法:求组合总和!](https://programmercarl.com/0216.组合总和III.html)。 -如果是多个集合取组合,各个集合之间相互不影响,那么就不用startIndex,例如:[回溯算法:电话号码的字母组合](https://mp.weixin.qq.com/s/e2ua2cmkE_vpYjM3j6HY0A) +如果是多个集合取组合,各个集合之间相互不影响,那么就不用startIndex,例如:[回溯算法:电话号码的字母组合](https://programmercarl.com/0017.电话号码的字母组合.html) **注意以上我只是说求组合的情况,如果是排列问题,又是另一套分析的套路**。 @@ -130,7 +130,7 @@ for (int i = startIndex; i < candidates.size() && sum + candidates[i] <= target; ### 组合总和(三) -在[回溯算法:求组合总和(三)](https://mp.weixin.qq.com/s/_1zPYk70NvHsdY8UWVGXmQ)中集合元素会有重复,但要求解集不能包含重复的组合。 +在[回溯算法:求组合总和(三)](https://programmercarl.com/0040.组合总和II.html)中集合元素会有重复,但要求解集不能包含重复的组合。 **所以难就难在去重问题上了**。 @@ -153,11 +153,11 @@ for (int i = startIndex; i < candidates.size() && sum + candidates[i] <= target; ## 多个集合求组合 -在[回溯算法:电话号码的字母组合](https://mp.weixin.qq.com/s/e2ua2cmkE_vpYjM3j6HY0A)中,开始用多个集合来求组合,还是熟悉的模板题目,但是有一些细节。 +在[回溯算法:电话号码的字母组合](https://programmercarl.com/0017.电话号码的字母组合.html)中,开始用多个集合来求组合,还是熟悉的模板题目,但是有一些细节。 -例如这里for循环,可不像是在 [回溯算法:求组合问题!](https://mp.weixin.qq.com/s/OnBjbLzuipWz_u4QfmgcqQ)和[回溯算法:求组合总和!](https://mp.weixin.qq.com/s/HX7WW6ixbFZJASkRnCTC3w)中从startIndex开始遍历的。 +例如这里for循环,可不像是在 [回溯算法:求组合问题!](https://programmercarl.com/0077.组合.html)和[回溯算法:求组合总和!](https://programmercarl.com/0216.组合总和III.html)中从startIndex开始遍历的。 -**因为本题每一个数字代表的是不同集合,也就是求不同集合之间的组合,而[回溯算法:求组合问题!](https://mp.weixin.qq.com/s/OnBjbLzuipWz_u4QfmgcqQ)和[回溯算法:求组合总和!](https://mp.weixin.qq.com/s/HX7WW6ixbFZJASkRnCTC3w)都是是求同一个集合中的组合!** +**因为本题每一个数字代表的是不同集合,也就是求不同集合之间的组合,而[回溯算法:求组合问题!](https://programmercarl.com/0077.组合.html)和[回溯算法:求组合总和!](https://programmercarl.com/0216.组合总和III.html)都是是求同一个集合中的组合!** 树形结构如下: @@ -169,7 +169,7 @@ for (int i = startIndex; i < candidates.size() && sum + candidates[i] <= target; # 切割问题 -在[回溯算法:分割回文串](https://mp.weixin.qq.com/s/Pb1epUTbU8fHIht-g_MS5Q)中,我们开始讲解切割问题,虽然最后代码看起来好像是一道模板题,但是从分析到学会套用这个模板,是比较难的。 +在[回溯算法:分割回文串](https://programmercarl.com/0131.分割回文串.html)中,我们开始讲解切割问题,虽然最后代码看起来好像是一道模板题,但是从分析到学会套用这个模板,是比较难的。 我列出如下几个难点: @@ -196,7 +196,7 @@ for (int i = startIndex; i < candidates.size() && sum + candidates[i] <= target; ## 子集问题(一) -在[回溯算法:求子集问题!](https://mp.weixin.qq.com/s/NNRzX-vJ_pjK4qxohd_LtA)中讲解了子集问题,**在树形结构中子集问题是要收集所有节点的结果,而组合问题是收集叶子节点的结果**。 +在[回溯算法:求子集问题!](https://programmercarl.com/0078.子集.html)中讲解了子集问题,**在树形结构中子集问题是要收集所有节点的结果,而组合问题是收集叶子节点的结果**。 如图: @@ -221,9 +221,9 @@ if (startIndex >= nums.size()) { // 终止条件可以不加 ## 子集问题(二) -在[回溯算法:求子集问题(二)](https://mp.weixin.qq.com/s/WJ4JNDRJgsW3eUN72Hh3uQ)中,开始针对子集问题进行去重。 +在[回溯算法:求子集问题(二)](https://programmercarl.com/0090.子集II.html)中,开始针对子集问题进行去重。 -本题就是[回溯算法:求子集问题!](https://mp.weixin.qq.com/s/NNRzX-vJ_pjK4qxohd_LtA)的基础上加上了去重,去重我们在[回溯算法:求组合总和(三)](https://mp.weixin.qq.com/s/_1zPYk70NvHsdY8UWVGXmQ)也讲过了,一样的套路。 +本题就是[回溯算法:求子集问题!](https://programmercarl.com/0078.子集.html)的基础上加上了去重,去重我们在[回溯算法:求组合总和(三)](https://programmercarl.com/0040.组合总和II.html)也讲过了,一样的套路。 树形结构如下: @@ -231,15 +231,15 @@ if (startIndex >= nums.size()) { // 终止条件可以不加 ## 递增子序列 -在[回溯算法:递增子序列](https://mp.weixin.qq.com/s/ePxOtX1ATRYJb2Jq7urzHQ)中,处处都能看到子集的身影,但处处是陷阱,值得好好琢磨琢磨! +在[回溯算法:递增子序列](https://programmercarl.com/0491.递增子序列.html)中,处处都能看到子集的身影,但处处是陷阱,值得好好琢磨琢磨! 树形结构如下: ![491. 递增子序列1](https://img-blog.csdnimg.cn/20201112170832333.png) -很多同学都会把这道题目和[回溯算法:求子集问题(二)](https://mp.weixin.qq.com/s/WJ4JNDRJgsW3eUN72Hh3uQ)混在一起。 +很多同学都会把这道题目和[回溯算法:求子集问题(二)](https://programmercarl.com/0090.子集II.html)混在一起。 -**[回溯算法:求子集问题(二)](https://mp.weixin.qq.com/s/WJ4JNDRJgsW3eUN72Hh3uQ)也可以使用set针对同一父节点本层去重,但子集问题一定要排序,为什么呢?** +**[回溯算法:求子集问题(二)](https://programmercarl.com/0090.子集II.html)也可以使用set针对同一父节点本层去重,但子集问题一定要排序,为什么呢?** 我用没有排序的集合{2,1,2,2}来举个例子画一个图,如下: @@ -251,7 +251,7 @@ if (startIndex >= nums.size()) { // 终止条件可以不加 ## 排列问题(一) -[回溯算法:排列问题!](https://mp.weixin.qq.com/s/SCOjeMX1t41wcvJq49GhMw) 又不一样了。 +[回溯算法:排列问题!](https://programmercarl.com/0046.全排列.html) 又不一样了。 排列是有序的,也就是说[1,2] 和[2,1] 是两个集合,这和之前分析的子集以及组合所不同的地方。 @@ -268,7 +268,7 @@ if (startIndex >= nums.size()) { // 终止条件可以不加 ## 排列问题(二) -排列问题也要去重了,在[回溯算法:排列问题(二)](https://mp.weixin.qq.com/s/9L8h3WqRP_h8LLWNT34YlA)中又一次强调了“树层去重”和“树枝去重”。 +排列问题也要去重了,在[回溯算法:排列问题(二)](https://programmercarl.com/0047.全排列II.html)中又一次强调了“树层去重”和“树枝去重”。 树形结构如下: @@ -294,17 +294,17 @@ if (startIndex >= nums.size()) { // 终止条件可以不加 以上我都是统一使用used数组来去重的,其实使用set也可以用来去重! -在[本周小结!(回溯算法系列三)续集](https://mp.weixin.qq.com/s/kSMGHc_YpsqL2j-jb_E_Ag)中给出了子集、组合、排列问题使用set来去重的解法以及具体代码,并纠正一些同学的常见错误写法。 +在[本周小结!(回溯算法系列三)续集](https://programmercarl.com/回溯算法去重问题的另一种写法.html)中给出了子集、组合、排列问题使用set来去重的解法以及具体代码,并纠正一些同学的常见错误写法。 同时详细分析了 使用used数组去重 和 使用set去重 两种写法的性能差异: **使用set去重的版本相对于used数组的版本效率都要低很多**,大家在leetcode上提交,能明显发现。 -原因在[回溯算法:递增子序列](https://mp.weixin.qq.com/s/ePxOtX1ATRYJb2Jq7urzHQ)中也分析过,主要是因为程序运行的时候对unordered_set 频繁的insert,unordered_set需要做哈希映射(也就是把key通过hash function映射为唯一的哈希值)相对费时间,而且insert的时候其底层的符号表也要做相应的扩充,也是费时的。 +原因在[回溯算法:递增子序列](https://programmercarl.com/0491.递增子序列.html)中也分析过,主要是因为程序运行的时候对unordered_set 频繁的insert,unordered_set需要做哈希映射(也就是把key通过hash function映射为唯一的哈希值)相对费时间,而且insert的时候其底层的符号表也要做相应的扩充,也是费时的。 **而使用used数组在时间复杂度上几乎没有额外负担!** -**使用set去重,不仅时间复杂度高了,空间复杂度也高了**,在[本周小结!(回溯算法系列三)](https://mp.weixin.qq.com/s/tLkt9PSo42X60w8i94ViiA)中分析过,组合,子集,排列问题的空间复杂度都是O(n),但如果使用set去重,空间复杂度就变成了O(n^2),因为每一层递归都有一个set集合,系统栈空间是n,每一个空间都有set集合。 +**使用set去重,不仅时间复杂度高了,空间复杂度也高了**,在[本周小结!(回溯算法系列三)](https://programmercarl.com/周总结/20201112回溯周末总结.html)中分析过,组合,子集,排列问题的空间复杂度都是O(n),但如果使用set去重,空间复杂度就变成了O(n^2),因为每一层递归都有一个set集合,系统栈空间是n,每一个空间都有set集合。 那有同学可能疑惑 用used数组也是占用O(n)的空间啊? @@ -314,7 +314,7 @@ used数组可是全局变量,每层与每层之间公用一个used数组,所 之前说过,有递归的地方就有回溯,深度优先搜索也是用递归来实现的,所以往往伴随着回溯。 -在[回溯算法:重新安排行程](https://mp.weixin.qq.com/s/3kmbS4qDsa6bkyxR92XCTA)其实也算是图论里深搜的题目,但是我用回溯法的套路来讲解这道题目,算是给大家拓展一下思路,原来回溯法还可以这么玩! +在[回溯算法:重新安排行程](https://programmercarl.com/0332.重新安排行程.html)其实也算是图论里深搜的题目,但是我用回溯法的套路来讲解这道题目,算是给大家拓展一下思路,原来回溯法还可以这么玩! 以输入:[["JFK", "KUL"], ["JFK", "NRT"], ["NRT", "JFK"]为例,抽象为树形结构如下: @@ -331,7 +331,7 @@ used数组可是全局变量,每层与每层之间公用一个used数组,所 ## N皇后问题 -在[回溯算法:N皇后问题](https://mp.weixin.qq.com/s/lU_QwCMj6g60nh8m98GAWg)中终于迎来了传说中的N皇后。 +在[回溯算法:N皇后问题](https://programmercarl.com/0051.N皇后.html)中终于迎来了传说中的N皇后。 下面我用一个3 * 3 的棋牌,将搜索过程抽象为一颗树,如图: @@ -345,19 +345,19 @@ used数组可是全局变量,每层与每层之间公用一个used数组,所 **这里我明确给出了棋盘的宽度就是for循环的长度,递归的深度就是棋盘的高度,这样就可以套进回溯法的模板里了**。 -相信看完本篇[回溯算法:N皇后问题](https://mp.weixin.qq.com/s/lU_QwCMj6g60nh8m98GAWg)也没那么难了,传说已经不是传说了,哈哈。 +相信看完本篇[回溯算法:N皇后问题](https://programmercarl.com/0051.N皇后.html)也没那么难了,传说已经不是传说了,哈哈。 ## 解数独问题 -在[回溯算法:解数独](https://mp.weixin.qq.com/s/eWE9TapVwm77yW9Q81xSZQ)中要征服回溯法的最后一道山峰。 +在[回溯算法:解数独](https://programmercarl.com/0037.解数独.html)中要征服回溯法的最后一道山峰。 解数独应该是棋盘很难的题目了,比N皇后还要复杂一些,但只要理解 “二维递归”这个过程,其实发现就没那么难了。 -大家已经跟着「代码随想录」刷过了如下回溯法题目,例如:[77.组合(组合问题)](https://mp.weixin.qq.com/s/OnBjbLzuipWz_u4QfmgcqQ),[131.分割回文串(分割问题)](https://mp.weixin.qq.com/s/Pb1epUTbU8fHIht-g_MS5Q),[78.子集(子集问题)](https://mp.weixin.qq.com/s/NNRzX-vJ_pjK4qxohd_LtA),[46.全排列(排列问题)](https://mp.weixin.qq.com/s/SCOjeMX1t41wcvJq49GhMw),以及[51.N皇后(N皇后问题)](https://mp.weixin.qq.com/s/lU_QwCMj6g60nh8m98GAWg),其实这些题目都是一维递归。 +大家已经跟着「代码随想录」刷过了如下回溯法题目,例如:[77.组合(组合问题)](https://programmercarl.com/0077.组合.html),[131.分割回文串(分割问题)](https://programmercarl.com/0131.分割回文串.html),[78.子集(子集问题)](https://programmercarl.com/0078.子集.html),[46.全排列(排列问题)](https://programmercarl.com/0046.全排列.html),以及[51.N皇后(N皇后问题)](https://programmercarl.com/0051.N皇后.html),其实这些题目都是一维递归。 -其中[N皇后问题](https://mp.weixin.qq.com/s/lU_QwCMj6g60nh8m98GAWg)是因为每一行每一列只放一个皇后,只需要一层for循环遍历一行,递归来遍历列,然后一行一列确定皇后的唯一位置。 +其中[N皇后问题](https://programmercarl.com/0051.N皇后.html)是因为每一行每一列只放一个皇后,只需要一层for循环遍历一行,递归来遍历列,然后一行一列确定皇后的唯一位置。 本题就不一样了,**本题中棋盘的每一个位置都要放一个数字,并检查数字是否合法,解数独的树形结构要比N皇后更宽更深**。 @@ -367,7 +367,7 @@ used数组可是全局变量,每层与每层之间公用一个used数组,所 解数独可以说是非常难的题目了,如果还一直停留在一维递归的逻辑中,这道题目可以让大家瞬间崩溃。 -**所以我在[回溯算法:解数独](https://mp.weixin.qq.com/s/eWE9TapVwm77yW9Q81xSZQ)中开篇就提到了二维递归,这也是我自创词汇**,希望可以帮助大家理解解数独的搜索过程。 +**所以我在[回溯算法:解数独](https://programmercarl.com/0037.解数独.html)中开篇就提到了二维递归,这也是我自创词汇**,希望可以帮助大家理解解数独的搜索过程。 一波分析之后,在看代码会发现其实也不难,唯一难点就是理解**二维递归**的思维逻辑。 diff --git a/problems/回溯算法去重问题的另一种写法.md b/problems/回溯算法去重问题的另一种写法.md index cc563fb1..d267d23c 100644 --- a/problems/回溯算法去重问题的另一种写法.md +++ b/problems/回溯算法去重问题的另一种写法.md @@ -8,13 +8,13 @@ # 回溯算法去重问题的另一种写法 -> 在 [本周小结!(回溯算法系列三)](https://mp.weixin.qq.com/s/tLkt9PSo42X60w8i94ViiA) 中一位录友对 整颗树的本层和同一节点的本层有疑问,也让我重新思考了一下,发现这里确实有问题,所以专门写一篇来纠正,感谢录友们的积极交流哈! +> 在 [本周小结!(回溯算法系列三)](https://programmercarl.com/周总结/20201112回溯周末总结.html) 中一位录友对 整颗树的本层和同一节点的本层有疑问,也让我重新思考了一下,发现这里确实有问题,所以专门写一篇来纠正,感谢录友们的积极交流哈! 接下来我再把这块再讲一下。 -在[回溯算法:求子集问题(二)](https://mp.weixin.qq.com/s/WJ4JNDRJgsW3eUN72Hh3uQ)中的去重和 [回溯算法:递增子序列](https://mp.weixin.qq.com/s/ePxOtX1ATRYJb2Jq7urzHQ)中的去重 都是 同一父节点下本层的去重。 +在[回溯算法:求子集问题(二)](https://programmercarl.com/0090.子集II.html)中的去重和 [回溯算法:递增子序列](https://programmercarl.com/0491.递增子序列.html)中的去重 都是 同一父节点下本层的去重。 -[回溯算法:求子集问题(二)](https://mp.weixin.qq.com/s/WJ4JNDRJgsW3eUN72Hh3uQ)也可以使用set针对同一父节点本层去重,但子集问题一定要排序,为什么呢? +[回溯算法:求子集问题(二)](https://programmercarl.com/0090.子集II.html)也可以使用set针对同一父节点本层去重,但子集问题一定要排序,为什么呢? 我用没有排序的集合{2,1,2,2}来举例子画一个图,如图: @@ -22,11 +22,11 @@ 图中,大家就很明显的看到,子集重复了。 -那么下面我针对[回溯算法:求子集问题(二)](https://mp.weixin.qq.com/s/WJ4JNDRJgsW3eUN72Hh3uQ) 给出使用set来对本层去重的代码实现。 +那么下面我针对[回溯算法:求子集问题(二)](https://programmercarl.com/0090.子集II.html) 给出使用set来对本层去重的代码实现。 ## 90.子集II -used数组去重版本: [回溯算法:求子集问题(二)](https://mp.weixin.qq.com/s/WJ4JNDRJgsW3eUN72Hh3uQ) +used数组去重版本: [回溯算法:求子集问题(二)](https://programmercarl.com/0090.子集II.html) 使用set去重的版本如下: @@ -138,7 +138,7 @@ uset已经是全局变量,本层的uset记录了一个元素,然后进入下 ## 40. 组合总和 II -使用used数组去重版本:[回溯算法:求组合总和(三)](https://mp.weixin.qq.com/s/_1zPYk70NvHsdY8UWVGXmQ) +使用used数组去重版本:[回溯算法:求组合总和(三)](https://programmercarl.com/0040.组合总和II.html) 使用set去重的版本如下: @@ -179,7 +179,7 @@ public: ## 47. 全排列 II -使用used数组去重版本:[回溯算法:排列问题(二)](https://mp.weixin.qq.com/s/9L8h3WqRP_h8LLWNT34YlA) +使用used数组去重版本:[回溯算法:排列问题(二)](https://programmercarl.com/0047.全排列II.html) 使用set去重的版本如下: @@ -224,11 +224,11 @@ public: 需要注意的是:**使用set去重的版本相对于used数组的版本效率都要低很多**,大家在leetcode上提交,能明显发现。 -原因在[回溯算法:递增子序列](https://mp.weixin.qq.com/s/ePxOtX1ATRYJb2Jq7urzHQ)中也分析过,主要是因为程序运行的时候对unordered_set 频繁的insert,unordered_set需要做哈希映射(也就是把key通过hash function映射为唯一的哈希值)相对费时间,而且insert的时候其底层的符号表也要做相应的扩充,也是费时的。 +原因在[回溯算法:递增子序列](https://programmercarl.com/0491.递增子序列.html)中也分析过,主要是因为程序运行的时候对unordered_set 频繁的insert,unordered_set需要做哈希映射(也就是把key通过hash function映射为唯一的哈希值)相对费时间,而且insert的时候其底层的符号表也要做相应的扩充,也是费时的。 **而使用used数组在时间复杂度上几乎没有额外负担!** -**使用set去重,不仅时间复杂度高了,空间复杂度也高了**,在[本周小结!(回溯算法系列三)](https://mp.weixin.qq.com/s/tLkt9PSo42X60w8i94ViiA)中分析过,组合,子集,排列问题的空间复杂度都是O(n),但如果使用set去重,空间复杂度就变成了O(n^2),因为每一层递归都有一个set集合,系统栈空间是n,每一个空间都有set集合。 +**使用set去重,不仅时间复杂度高了,空间复杂度也高了**,在[本周小结!(回溯算法系列三)](https://programmercarl.com/周总结/20201112回溯周末总结.html)中分析过,组合,子集,排列问题的空间复杂度都是O(n),但如果使用set去重,空间复杂度就变成了O(n^2),因为每一层递归都有一个set集合,系统栈空间是n,每一个空间都有set集合。 那有同学可能疑惑 用used数组也是占用O(n)的空间啊? @@ -236,7 +236,7 @@ used数组可是全局变量,每层与每层之间公用一个used数组,所 ## 总结 -本篇本打算是对[本周小结!(回溯算法系列三)](https://mp.weixin.qq.com/s/tLkt9PSo42X60w8i94ViiA)的一个点做一下纠正,没想到又写出来这么多! +本篇本打算是对[本周小结!(回溯算法系列三)](https://programmercarl.com/周总结/20201112回溯周末总结.html)的一个点做一下纠正,没想到又写出来这么多! **这个点都源于一位录友的疑问,然后我思考总结了一下,就写着这一篇,所以还是得多交流啊!** diff --git a/problems/回溯算法理论基础.md b/problems/回溯算法理论基础.md index b86c2506..29981c66 100644 --- a/problems/回溯算法理论基础.md +++ b/problems/回溯算法理论基础.md @@ -13,7 +13,7 @@ 回溯法也可以叫做回溯搜索法,它是一种搜索的方式。 -在二叉树系列中,我们已经不止一次,提到了回溯,例如[二叉树:以为使用了递归,其实还隐藏着回溯](https://mp.weixin.qq.com/s/ivLkHzWdhjQQD1rQWe6zWA)。 +在二叉树系列中,我们已经不止一次,提到了回溯,例如[二叉树:以为使用了递归,其实还隐藏着回溯](https://programmercarl.com/二叉树中递归带着回溯.html)。 回溯是递归的副产品,只要有递归就会有回溯。 @@ -67,7 +67,7 @@ 这里给出Carl总结的回溯算法模板。 -在讲[二叉树的递归](https://mp.weixin.qq.com/s/PwVIfxDlT3kRgMASWAMGhA)中我们说了递归三部曲,这里我再给大家列出回溯三部曲。 +在讲[二叉树的递归](https://programmercarl.com/二叉树的递归遍历.html)中我们说了递归三部曲,这里我再给大家列出回溯三部曲。 * 回溯函数模板返回值以及参数 @@ -87,7 +87,7 @@ void backtracking(参数) * 回溯函数终止条件 -既然是树形结构,那么我们在讲解[二叉树的递归](https://mp.weixin.qq.com/s/PwVIfxDlT3kRgMASWAMGhA)的时候,就知道遍历树形结构一定要有终止条件。 +既然是树形结构,那么我们在讲解[二叉树的递归](https://programmercarl.com/二叉树的递归遍历.html)的时候,就知道遍历树形结构一定要有终止条件。 所以回溯也有要终止条件。 diff --git a/problems/字符串总结.md b/problems/字符串总结.md index f9c9766e..57ac9a31 100644 --- a/problems/字符串总结.md +++ b/problems/字符串总结.md @@ -46,7 +46,7 @@ for (int i = 0; i < a.size(); i++) { # 要不要使用库函数 -在文章[344.反转字符串](https://mp.weixin.qq.com/s/_rNm66OJVl92gBDIbGpA3w)中强调了**打基础的时候,不要太迷恋于库函数。** +在文章[344.反转字符串](https://programmercarl.com/0344.反转字符串.html)中强调了**打基础的时候,不要太迷恋于库函数。** 甚至一些同学习惯于调用substr,split,reverse之类的库函数,却不知道其实现原理,也不知道其时间复杂度,这样实现出来的代码,如果在面试现场,面试官问:“分析其时间复杂度”的话,一定会一脸懵逼! @@ -57,15 +57,15 @@ for (int i = 0; i < a.size(); i++) { # 双指针法 -在[344.反转字符串](https://mp.weixin.qq.com/s/_rNm66OJVl92gBDIbGpA3w) ,我们使用双指针法实现了反转字符串的操作,**双指针法在数组,链表和字符串中很常用。** +在[344.反转字符串](https://programmercarl.com/0344.反转字符串.html) ,我们使用双指针法实现了反转字符串的操作,**双指针法在数组,链表和字符串中很常用。** -接着在[字符串:替换空格](https://mp.weixin.qq.com/s/69HNjR4apcRSAo_KyknPjA),同样还是使用双指针法在时间复杂度O(n)的情况下完成替换空格。 +接着在[字符串:替换空格](https://programmercarl.com/剑指Offer05.替换空格.html),同样还是使用双指针法在时间复杂度O(n)的情况下完成替换空格。 **其实很多数组填充类的问题,都可以先预先给数组扩容带填充后的大小,然后在从后向前进行操作。** -那么针对数组删除操作的问题,其实在[27. 移除元素](https://mp.weixin.qq.com/s/RMkulE4NIb6XsSX83ra-Ww)中就已经提到了使用双指针法进行移除操作。 +那么针对数组删除操作的问题,其实在[27. 移除元素](https://programmercarl.com/0027.移除元素.html)中就已经提到了使用双指针法进行移除操作。 -同样的道理在[151.翻转字符串里的单词](https://mp.weixin.qq.com/s/4j6vPFHkFAXnQhmSkq2X9g)中我们使用O(n)的时间复杂度,完成了删除冗余空格。 +同样的道理在[151.翻转字符串里的单词](https://programmercarl.com/0151.翻转字符串里的单词.html)中我们使用O(n)的时间复杂度,完成了删除冗余空格。 一些同学会使用for循环里调用库函数erase来移除元素,这其实是O(n^2)的操作,因为erase就是O(n)的操作,所以这也是典型的不知道库函数的时间复杂度,上来就用的案例了。 @@ -73,7 +73,7 @@ for (int i = 0; i < a.size(); i++) { 在反转上还可以在加一些玩法,其实考察的是对代码的掌控能力。 -[541. 反转字符串II](https://mp.weixin.qq.com/s/pzXt6PQ029y7bJ9YZB2mVQ)中,一些同学可能为了处理逻辑:每隔2k个字符的前k的字符,写了一堆逻辑代码或者再搞一个计数器,来统计2k,再统计前k个字符。 +[541. 反转字符串II](https://programmercarl.com/0541.反转字符串II.html)中,一些同学可能为了处理逻辑:每隔2k个字符的前k的字符,写了一堆逻辑代码或者再搞一个计数器,来统计2k,再统计前k个字符。 其实**当需要固定规律一段一段去处理字符串的时候,要想想在在for循环的表达式上做做文章**。 @@ -81,26 +81,26 @@ for (int i = 0; i < a.size(); i++) { 因为要找的也就是每2 * k 区间的起点,这样写程序会高效很多。 -在[151.翻转字符串里的单词](https://mp.weixin.qq.com/s/4j6vPFHkFAXnQhmSkq2X9g)中要求翻转字符串里的单词,这道题目可以说是综合考察了字符串的多种操作。是考察字符串的好题。 +在[151.翻转字符串里的单词](https://programmercarl.com/0151.翻转字符串里的单词.html)中要求翻转字符串里的单词,这道题目可以说是综合考察了字符串的多种操作。是考察字符串的好题。 这道题目通过 **先整体反转再局部反转**,实现了反转字符串里的单词。 后来发现反转字符串还有一个牛逼的用处,就是达到左旋的效果。 -在[字符串:反转个字符串还有这个用处?](https://mp.weixin.qq.com/s/Px_L-RfT2b_jXKcNmccPsw)中,我们通过**先局部反转再整体反转**达到了左旋的效果。 +在[字符串:反转个字符串还有这个用处?](https://programmercarl.com/剑指Offer58-II.左旋转字符串.html)中,我们通过**先局部反转再整体反转**达到了左旋的效果。 # KMP KMP的主要思想是**当出现字符串不匹配时,可以知道一部分之前已经匹配的文本内容,可以利用这些信息避免从头再去做匹配了。** -KMP的精髓所在就是前缀表,在[KMP精讲](https://mp.weixin.qq.com/s/MoRBHbS4hQXn7LcPdmHmIg)中提到了,什么是KMP,什么是前缀表,以及为什么要用前缀表。 +KMP的精髓所在就是前缀表,在[KMP精讲](https://programmercarl.com/0028.实现strStr.html)中提到了,什么是KMP,什么是前缀表,以及为什么要用前缀表。 前缀表:起始位置到下表i之前(包括i)的子串中,有多大长度的相同前缀后缀。 那么使用KMP可以解决两类经典问题: -1. 匹配问题:[28. 实现 strStr()](https://mp.weixin.qq.com/s/MoRBHbS4hQXn7LcPdmHmIg) -2. 重复子串问题:[459.重复的子字符串](https://mp.weixin.qq.com/s/32Pve4j8IWvdgxYEZdTeFg) +1. 匹配问题:[28. 实现 strStr()](https://programmercarl.com/0028.实现strStr.html) +2. 重复子串问题:[459.重复的子字符串](https://programmercarl.com/0459.重复的子字符串.html) 再一次强调了什么是前缀,什么是后缀,什么又是最长相等前后缀。 @@ -108,7 +108,7 @@ KMP的精髓所在就是前缀表,在[KMP精讲](https://mp.weixin.qq.com/s/Mo 后缀:指不包含第一个字符的所有以最后一个字符结尾的连续子串。 -然后**针对前缀表到底要不要减一,这其实是不同KMP实现的方式**,我们在[KMP精讲](https://mp.weixin.qq.com/s/MoRBHbS4hQXn7LcPdmHmIg)中针对之前两个问题,分别给出了两个不同版本的的KMP实现。 +然后**针对前缀表到底要不要减一,这其实是不同KMP实现的方式**,我们在[KMP精讲](https://programmercarl.com/0028.实现strStr.html)中针对之前两个问题,分别给出了两个不同版本的的KMP实现。 其中主要**理解j=next[x]这一步最为关键!** diff --git a/problems/数组总结篇.md b/problems/数组总结篇.md index 009cc6f2..7fafb94b 100644 --- a/problems/数组总结篇.md +++ b/problems/数组总结篇.md @@ -63,7 +63,7 @@ ## 二分法 -[数组:每次遇到二分法,都是一看就会,一写就废](https://mp.weixin.qq.com/s/fCf5QbPDtE6SSlZ1yh_q8Q) +[数组:每次遇到二分法,都是一看就会,一写就废](https://programmercarl.com/0704.二分查找.html) 这道题目呢,考察的数据的基本操作,思路很简单,但是在通过率在简单题里并不高,不要轻敌。 @@ -79,7 +79,7 @@ ## 双指针法 -* [数组:就移除个元素很难么?](https://mp.weixin.qq.com/s/wj0T-Xs88_FHJFwayElQlA) +* [数组:就移除个元素很难么?](https://programmercarl.com/0027.移除元素.html) 双指针法(快慢指针法):**通过一个快指针和慢指针在一个for循环下完成两个for循环的工作。** @@ -95,7 +95,7 @@ ## 滑动窗口 -* [数组:滑动窗口拯救了你](https://mp.weixin.qq.com/s/UrZynlqi4QpyLlLhBPglyg) +* [数组:滑动窗口拯救了你](https://programmercarl.com/0209.长度最小的子数组.html) 本题介绍了数组操作中的另一个重要思想:滑动窗口。 @@ -111,7 +111,7 @@ ## 模拟行为 -* [数组:这个循环可以转懵很多人!](https://mp.weixin.qq.com/s/KTPhaeqxbMK9CxHUUgFDmg) +* [数组:这个循环可以转懵很多人!](https://programmercarl.com/0059.螺旋矩阵II.html) 模拟类的题目在数组中很常见,不涉及到什么算法,就是单纯的模拟,十分考察大家对代码的掌控能力。 diff --git a/problems/栈与队列总结.md b/problems/栈与队列总结.md index 70ef7e9c..ffcd38a1 100644 --- a/problems/栈与队列总结.md +++ b/problems/栈与队列总结.md @@ -9,7 +9,7 @@ # 栈与队列的理论基础 -首先我们在[栈与队列:来看看栈和队列不为人知的一面](https://mp.weixin.qq.com/s/VZRjOccyE09aE-MgLbCMjQ)中讲解了栈和队列的理论基础。 +首先我们在[栈与队列:来看看栈和队列不为人知的一面](https://programmercarl.com/栈与队列理论基础.html)中讲解了栈和队列的理论基础。 里面提到了灵魂四问: @@ -33,9 +33,9 @@ 大家还是要多多重视起来! -了解了栈与队列基础之后,那么可以用[栈与队列:栈实现队列](https://mp.weixin.qq.com/s/P6tupDwRFi6Ay-L7DT4NVg) 和 [栈与队列:队列实现栈](https://mp.weixin.qq.com/s/yzn6ktUlL-vRG3-m5a8_Yw) 来练习一下栈与队列的基本操作。 +了解了栈与队列基础之后,那么可以用[栈与队列:栈实现队列](https://programmercarl.com/0232.用栈实现队列.html) 和 [栈与队列:队列实现栈](https://programmercarl.com/0225.用队列实现栈.html) 来练习一下栈与队列的基本操作。 -值得一提的是,用[栈与队列:用队列实现栈还有点别扭](https://mp.weixin.qq.com/s/yzn6ktUlL-vRG3-m5a8_Yw)中,其实只用一个队列就够了。 +值得一提的是,用[栈与队列:用队列实现栈还有点别扭](https://programmercarl.com/0225.用队列实现栈.html)中,其实只用一个队列就够了。 **一个队列在模拟栈弹出元素的时候只要将队列头部的元素(除了最后一个元素外) 重新添加到队列尾部,此时在去弹出元素就是栈的顺序了。** @@ -63,7 +63,7 @@ cd a/b/c/../../ ## 括号匹配问题 -在[栈与队列:系统中处处都是栈的应用](https://mp.weixin.qq.com/s/nLlmPMsDCIWSqAtr0jbrpQ)中我们讲解了括号匹配问题。 +在[栈与队列:系统中处处都是栈的应用](https://programmercarl.com/0020.有效的括号.html)中我们讲解了括号匹配问题。 **括号匹配是使用栈解决的经典问题。** @@ -79,23 +79,23 @@ cd a/b/c/../../ ## 字符串去重问题 -在[栈与队列:匹配问题都是栈的强项](https://mp.weixin.qq.com/s/eynAEbUbZoAWrk0ZlEugqg)中讲解了字符串去重问题。 +在[栈与队列:匹配问题都是栈的强项](https://programmercarl.com/1047.删除字符串中的所有相邻重复项.html)中讲解了字符串去重问题。 1047. 删除字符串中的所有相邻重复项 思路就是可以把字符串顺序放到一个栈中,然后如果相同的话 栈就弹出,这样最后栈里剩下的元素都是相邻不相同的元素了。 ## 逆波兰表达式问题 -在[栈与队列:有没有想过计算机是如何处理表达式的?](https://mp.weixin.qq.com/s/hneh2nnLT91rR8ms2fm_kw)中讲解了求逆波兰表达式。 +在[栈与队列:有没有想过计算机是如何处理表达式的?](https://programmercarl.com/0150.逆波兰表达式求值.html)中讲解了求逆波兰表达式。 -本题中每一个子表达式要得出一个结果,然后拿这个结果再进行运算,那么**这岂不就是一个相邻字符串消除的过程,和[栈与队列:匹配问题都是栈的强项](https://mp.weixin.qq.com/s/eynAEbUbZoAWrk0ZlEugqg)中的对对碰游戏是不是就非常像了。** +本题中每一个子表达式要得出一个结果,然后拿这个结果再进行运算,那么**这岂不就是一个相邻字符串消除的过程,和[栈与队列:匹配问题都是栈的强项](https://programmercarl.com/1047.删除字符串中的所有相邻重复项.html)中的对对碰游戏是不是就非常像了。** # 队列的经典题目 ## 滑动窗口最大值问题 -在[栈与队列:滑动窗口里求最大值引出一个重要数据结构](https://mp.weixin.qq.com/s/8c6l2bO74xyMjph09gQtpA)中讲解了一种数据结构:单调队列。 +在[栈与队列:滑动窗口里求最大值引出一个重要数据结构](https://programmercarl.com/0239.滑动窗口最大值.html)中讲解了一种数据结构:单调队列。 这道题目还是比较绕的,如果第一次遇到这种题目,需要反复琢磨琢磨 @@ -123,7 +123,7 @@ cd a/b/c/../../ ## 求前 K 个高频元素 -在[栈与队列:求前 K 个高频元素和队列有啥关系?](https://mp.weixin.qq.com/s/8hMwxoE_BQRbzCc7CA8rng)中讲解了求前 K 个高频元素。 +在[栈与队列:求前 K 个高频元素和队列有啥关系?](https://programmercarl.com/0347.前K个高频元素.html)中讲解了求前 K 个高频元素。 通过求前 K 个高频元素,引出另一种队列就是**优先级队列**。 diff --git a/problems/根据身高重建队列(vector原理讲解).md b/problems/根据身高重建队列(vector原理讲解).md index baf7dcf5..dfc824fa 100644 --- a/problems/根据身高重建队列(vector原理讲解).md +++ b/problems/根据身高重建队列(vector原理讲解).md @@ -7,7 +7,7 @@

欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!

# 贪心算法:根据身高重建队列(续集) -在讲解[贪心算法:根据身高重建队列](https://mp.weixin.qq.com/s/-2TgZVdOwS-DvtbjjDEbfw)中,我们提到了使用vector(C++中的动态数组)来进行insert操作是费时的。 +在讲解[贪心算法:根据身高重建队列](https://programmercarl.com/0406.根据身高重建队列.html)中,我们提到了使用vector(C++中的动态数组)来进行insert操作是费时的。 但是在解释的过程中有不恰当的地方,所以来专门写一篇文章来详细说一说这个问题。 @@ -99,9 +99,9 @@ for (int i = 0; i < vec.size(); i++) { **同时也注意此时capicity和size的变化,关键的地方我都标红了**。 -而在[贪心算法:根据身高重建队列](https://mp.weixin.qq.com/s/-2TgZVdOwS-DvtbjjDEbfw)中,我们使用vector来做insert的操作,此时大家可会发现,**虽然表面上复杂度是O(n^2),但是其底层都不知道额外做了多少次全量拷贝了,所以算上vector的底层拷贝,整体时间复杂度可以认为是O(n^2 + t * n)级别的,t是底层拷贝的次数**。 +而在[贪心算法:根据身高重建队列](https://programmercarl.com/0406.根据身高重建队列.html)中,我们使用vector来做insert的操作,此时大家可会发现,**虽然表面上复杂度是O(n^2),但是其底层都不知道额外做了多少次全量拷贝了,所以算上vector的底层拷贝,整体时间复杂度可以认为是O(n^2 + t * n)级别的,t是底层拷贝的次数**。 -那么是不是可以直接确定好vector的大小,不让它在动态扩容了,例如在[贪心算法:根据身高重建队列](https://mp.weixin.qq.com/s/-2TgZVdOwS-DvtbjjDEbfw)中已经给出了有people.size这么多的人,可以定义好一个固定大小的vector,这样我们就可以控制vector,不让它底层动态扩容。 +那么是不是可以直接确定好vector的大小,不让它在动态扩容了,例如在[贪心算法:根据身高重建队列](https://programmercarl.com/0406.根据身高重建队列.html)中已经给出了有people.size这么多的人,可以定义好一个固定大小的vector,这样我们就可以控制vector,不让它底层动态扩容。 这种方法需要自己模拟插入的操作,不仅没有直接调用insert接口那么方便,需要手动模拟插入操作,而且效率也不高! @@ -147,7 +147,7 @@ public: 所以对于两种使用数组的方法一和方法三,也不好确定谁优,但一定都没有使用方法二链表的效率高! -一波分析之后,对于[贪心算法:根据身高重建队列](https://mp.weixin.qq.com/s/-2TgZVdOwS-DvtbjjDEbfw) ,大家就安心使用链表吧!别折腾了,哈哈,相当于我替大家折腾了一下。 +一波分析之后,对于[贪心算法:根据身高重建队列](https://programmercarl.com/0406.根据身高重建队列.html) ,大家就安心使用链表吧!别折腾了,哈哈,相当于我替大家折腾了一下。 ## 总结 diff --git a/problems/算法模板.md b/problems/算法模板.md index 8f6b053e..b56678ab 100644 --- a/problems/算法模板.md +++ b/problems/算法模板.md @@ -174,7 +174,7 @@ vector postorderTraversal(TreeNode* root) { ``` ### 广度优先遍历(队列) -相关题解:[0102.二叉树的层序遍历](https://github.com/youngyangyang04/leetcode/blob/master/problems/0102.二叉树的层序遍历.md) +相关题解:[0102.二叉树的层序遍历](https://programmercarl.com/0102.二叉树的层序遍历.html) ``` vector> levelOrder(TreeNode* root) { @@ -202,13 +202,13 @@ vector> levelOrder(TreeNode* root) { 可以直接解决如下题目: -* [0102.二叉树的层序遍历](https://github.com/youngyangyang04/leetcode/blob/master/problems/0102.二叉树的层序遍历.md) +* [0102.二叉树的层序遍历](https://programmercarl.com/0102.二叉树的层序遍历.html) * [0199.二叉树的右视图](https://github.com/youngyangyang04/leetcode/blob/master/problems/0199.二叉树的右视图.md) * [0637.二叉树的层平均值](https://github.com/youngyangyang04/leetcode/blob/master/problems/0637.二叉树的层平均值.md) -* [0104.二叉树的最大深度 (迭代法)](https://github.com/youngyangyang04/leetcode/blob/master/problems/0104.二叉树的最大深度.md) +* [0104.二叉树的最大深度 (迭代法)](https://programmercarl.com/0104.二叉树的最大深度.html) -* [0111.二叉树的最小深度(迭代法)]((https://github.com/youngyangyang04/leetcode/blob/master/problems/0111.二叉树的最小深度.md)) -* [0222.完全二叉树的节点个数(迭代法)](https://github.com/youngyangyang04/leetcode/blob/master/problems/0222.完全二叉树的节点个数.md) +* [0111.二叉树的最小深度(迭代法)](https://programmercarl.com/0111.二叉树的最小深度.html) +* [0222.完全二叉树的节点个数(迭代法)](https://programmercarl.com/0222.完全二叉树的节点个数.html) ### 二叉树深度 diff --git a/problems/背包总结篇.md b/problems/背包总结篇.md index 7ec2d6bf..f3732c8d 100644 --- a/problems/背包总结篇.md +++ b/problems/背包总结篇.md @@ -30,30 +30,30 @@ ## 背包递推公式 问能否能装满背包(或者最多装多少):dp[j] = max(dp[j], dp[j - nums[i]] + nums[i]); ,对应题目如下: -* [动态规划:416.分割等和子集](https://mp.weixin.qq.com/s/sYw3QtPPQ5HMZCJcT4EaLQ) -* [动态规划:1049.最后一块石头的重量 II](https://mp.weixin.qq.com/s/WbwAo3jaUaNJjvhHgq0BGg) +* [动态规划:416.分割等和子集](https://programmercarl.com/0416.分割等和子集.html) +* [动态规划:1049.最后一块石头的重量 II](https://programmercarl.com/1049.最后一块石头的重量II.html) 问装满背包有几种方法:dp[j] += dp[j - nums[i]] ,对应题目如下: -* [动态规划:494.目标和](https://mp.weixin.qq.com/s/2pWmaohX75gwxvBENS-NCw) -* [动态规划:518. 零钱兑换 II](https://mp.weixin.qq.com/s/PlowDsI4WMBOzf3q80AksQ) -* [动态规划:377.组合总和Ⅳ](https://mp.weixin.qq.com/s/Iixw0nahJWQgbqVNk8k6gA) -* [动态规划:70. 爬楼梯进阶版(完全背包)](https://mp.weixin.qq.com/s/e_wacnELo-2PG76EjrUakA) +* [动态规划:494.目标和](https://programmercarl.com/0494.目标和.html) +* [动态规划:518. 零钱兑换 II](https://programmercarl.com/0518.零钱兑换II.html) +* [动态规划:377.组合总和Ⅳ](https://programmercarl.com/0377.组合总和Ⅳ.html) +* [动态规划:70. 爬楼梯进阶版(完全背包)](https://programmercarl.com/0070.爬楼梯完全背包版本.html) 问背包装满最大价值:dp[j] = max(dp[j], dp[j - weight[i]] + value[i]); ,对应题目如下: -* [动态规划:474.一和零](https://mp.weixin.qq.com/s/x-u3Dsp76DlYqtCe0xEKJw) +* [动态规划:474.一和零](https://programmercarl.com/0474.一和零.html) 问装满背包所有物品的最小个数:dp[j] = min(dp[j - coins[i]] + 1, dp[j]); ,对应题目如下: -* [动态规划:322.零钱兑换](https://mp.weixin.qq.com/s/dyk-xNilHzNtVdPPLObSeQ) -* [动态规划:279.完全平方数](https://mp.weixin.qq.com/s/VfJT78p7UGpDZsapKF_QJQ) +* [动态规划:322.零钱兑换](https://programmercarl.com/0322.零钱兑换.html) +* [动态规划:279.完全平方数](https://programmercarl.com/0279.完全平方数.html) ## 遍历顺序 ### 01背包 -在[动态规划:关于01背包问题,你该了解这些!](https://mp.weixin.qq.com/s/FwIiPPmR18_AJO5eiidT6w)中我们讲解二维dp数组01背包先遍历物品还是先遍历背包都是可以的,且第二层for循环是从小到大遍历。 +在[动态规划:关于01背包问题,你该了解这些!](https://programmercarl.com/背包理论基础01背包-1.html)中我们讲解二维dp数组01背包先遍历物品还是先遍历背包都是可以的,且第二层for循环是从小到大遍历。 -和[动态规划:关于01背包问题,你该了解这些!(滚动数组)](https://mp.weixin.qq.com/s/M4uHxNVKRKm5HPjkNZBnFA)中,我们讲解一维dp数组01背包只能先遍历物品再遍历背包容量,且第二层for循环是从大到小遍历。 +和[动态规划:关于01背包问题,你该了解这些!(滚动数组)](https://programmercarl.com/背包理论基础01背包-2.html)中,我们讲解一维dp数组01背包只能先遍历物品再遍历背包容量,且第二层for循环是从大到小遍历。 **一维dp数组的背包在遍历顺序上和二维dp数组实现的01背包其实是有很大差异的,大家需要注意!** @@ -61,7 +61,7 @@ 说完01背包,再看看完全背包。 -在[动态规划:关于完全背包,你该了解这些!](https://mp.weixin.qq.com/s/akwyxlJ4TLvKcw26KB9uJw)中,讲解了纯完全背包的一维dp数组实现,先遍历物品还是先遍历背包都是可以的,且第二层for循环是从小到大遍历。 +在[动态规划:关于完全背包,你该了解这些!](https://programmercarl.com/背包问题理论基础完全背包.html)中,讲解了纯完全背包的一维dp数组实现,先遍历物品还是先遍历背包都是可以的,且第二层for循环是从小到大遍历。 但是仅仅是纯完全背包的遍历顺序是这样的,题目稍有变化,两个for循环的先后顺序就不一样了。 @@ -71,12 +71,12 @@ 相关题目如下: -* 求组合数:[动态规划:518.零钱兑换II](https://mp.weixin.qq.com/s/PlowDsI4WMBOzf3q80AksQ) -* 求排列数:[动态规划:377. 组合总和 Ⅳ](https://mp.weixin.qq.com/s/Iixw0nahJWQgbqVNk8k6gA)、[动态规划:70. 爬楼梯进阶版(完全背包)](https://mp.weixin.qq.com/s/e_wacnELo-2PG76EjrUakA) +* 求组合数:[动态规划:518.零钱兑换II](https://programmercarl.com/0518.零钱兑换II.html) +* 求排列数:[动态规划:377. 组合总和 Ⅳ](https://mp.weixin.qq.com/s/Iixw0nahJWQgbqVNk8k6gA)、[动态规划:70. 爬楼梯进阶版(完全背包)](https://programmercarl.com/0070.爬楼梯完全背包版本.html) 如果求最小数,那么两层for循环的先后顺序就无所谓了,相关题目如下: -* 求最小数:[动态规划:322. 零钱兑换](https://mp.weixin.qq.com/s/dyk-xNilHzNtVdPPLObSeQ)、[动态规划:279.完全平方数](https://mp.weixin.qq.com/s/VfJT78p7UGpDZsapKF_QJQ) +* 求最小数:[动态规划:322. 零钱兑换](https://programmercarl.com/0322.零钱兑换.html)、[动态规划:279.完全平方数](https://programmercarl.com/0279.完全平方数.html) **对于背包问题,其实递推公式算是容易的,难是难在遍历顺序上,如果把遍历顺序搞透,才算是真正理解了**。 @@ -88,7 +88,7 @@ **而且每一个点,我都给出了对应的力扣题目**。 -最后如果你想了解多重背包,可以看这篇[动态规划:关于多重背包,你该了解这些!](https://mp.weixin.qq.com/s/b-UUUmbvG7URWyCjQkiuuQ),力扣上还没有多重背包的题目,也不是面试考察的重点。 +最后如果你想了解多重背包,可以看这篇[动态规划:关于多重背包,你该了解这些!](https://programmercarl.com/背包问题理论基础多重背包.html),力扣上还没有多重背包的题目,也不是面试考察的重点。 如果把我本篇总结出来的内容都掌握的话,可以说对背包问题理解的就很深刻了,用来对付面试中的背包问题绰绰有余! diff --git a/problems/背包理论基础01背包-2.md b/problems/背包理论基础01背包-2.md index 4f1455e9..07f74186 100644 --- a/problems/背包理论基础01背包-2.md +++ b/problems/背包理论基础01背包-2.md @@ -8,7 +8,7 @@ # 动态规划:关于01背包问题,你该了解这些!(滚动数组) -昨天[动态规划:关于01背包问题,你该了解这些!](https://mp.weixin.qq.com/s/FwIiPPmR18_AJO5eiidT6w)中是用二维dp数组来讲解01背包。 +昨天[动态规划:关于01背包问题,你该了解这些!](https://programmercarl.com/背包理论基础01背包-1.html)中是用二维dp数组来讲解01背包。 今天我们就来说一说滚动数组,其实在前面的题目中我们已经用到过滚动数组了,就是把二维dp降为一维dp,一些录友当时还表示比较困惑。 @@ -199,7 +199,7 @@ int main() { 大家可以发现其实信息量还是挺大的。 -如果把[动态规划:关于01背包问题,你该了解这些!](https://mp.weixin.qq.com/s/FwIiPPmR18_AJO5eiidT6w)和本篇的内容都理解了,后面我们在做01背包的题目,就会发现非常简单了。 +如果把[动态规划:关于01背包问题,你该了解这些!](https://programmercarl.com/背包理论基础01背包-1.html)和本篇的内容都理解了,后面我们在做01背包的题目,就会发现非常简单了。 不用再凭感觉或者记忆去写背包,而是有自己的思考,了解其本质,代码的方方面面都在自己的掌控之中。 diff --git a/problems/背包问题理论基础多重背包.md b/problems/背包问题理论基础多重背包.md index 85cbf4de..f1dfed26 100644 --- a/problems/背包问题理论基础多重背包.md +++ b/problems/背包问题理论基础多重背包.md @@ -9,9 +9,9 @@ 之前我们已经体统的讲解了01背包和完全背包,如果没有看过的录友,建议先把如下三篇文章仔细阅读一波。 -* [动态规划:关于01背包问题,你该了解这些!](https://mp.weixin.qq.com/s/FwIiPPmR18_AJO5eiidT6w) -* [动态规划:关于01背包问题,你该了解这些!(滚动数组)](https://mp.weixin.qq.com/s/M4uHxNVKRKm5HPjkNZBnFA) -* [动态规划:关于完全背包,你该了解这些!](https://mp.weixin.qq.com/s/akwyxlJ4TLvKcw26KB9uJw) +* [动态规划:关于01背包问题,你该了解这些!](https://programmercarl.com/背包理论基础01背包-1.html) +* [动态规划:关于01背包问题,你该了解这些!(滚动数组)](https://programmercarl.com/背包理论基础01背包-2.html) +* [动态规划:关于完全背包,你该了解这些!](https://programmercarl.com/背包问题理论基础完全背包.html) 这次我们再来说一说多重背包 diff --git a/problems/背包问题理论基础完全背包.md b/problems/背包问题理论基础完全背包.md index dc4f06f9..f4abc535 100644 --- a/problems/背包问题理论基础完全背包.md +++ b/problems/背包问题理论基础完全背包.md @@ -35,8 +35,8 @@ 关于01背包我如下两篇已经进行深入分析了: -* [动态规划:关于01背包问题,你该了解这些!](https://mp.weixin.qq.com/s/FwIiPPmR18_AJO5eiidT6w) -* [动态规划:关于01背包问题,你该了解这些!(滚动数组)](https://mp.weixin.qq.com/s/M4uHxNVKRKm5HPjkNZBnFA) +* [动态规划:关于01背包问题,你该了解这些!](https://programmercarl.com/背包理论基础01背包-1.html) +* [动态规划:关于01背包问题,你该了解这些!(滚动数组)](https://programmercarl.com/背包理论基础01背包-2.html) 首先在回顾一下01背包的核心代码 ``` @@ -61,7 +61,7 @@ for(int i = 0; i < weight.size(); i++) { // 遍历物品 } ``` -至于为什么,我在[动态规划:关于01背包问题,你该了解这些!(滚动数组)](https://mp.weixin.qq.com/s/M4uHxNVKRKm5HPjkNZBnFA)中也做了讲解。 +至于为什么,我在[动态规划:关于01背包问题,你该了解这些!(滚动数组)](https://programmercarl.com/背包理论基础01背包-2.html)中也做了讲解。 dp状态图如下: @@ -77,8 +77,8 @@ dp状态图如下: 看过这两篇的话: -* [动态规划:关于01背包问题,你该了解这些!](https://mp.weixin.qq.com/s/FwIiPPmR18_AJO5eiidT6w) -* [动态规划:关于01背包问题,你该了解这些!(滚动数组)](https://mp.weixin.qq.com/s/M4uHxNVKRKm5HPjkNZBnFA) +* [动态规划:关于01背包问题,你该了解这些!](https://programmercarl.com/背包理论基础01背包-1.html) +* [动态规划:关于01背包问题,你该了解这些!(滚动数组)](https://programmercarl.com/背包理论基础01背包-2.html) 就知道了,01背包中二维dp数组的两个for遍历的先后循序是可以颠倒了,一位dp数组的两个for循环先后循序一定是先遍历物品,再遍历背包容量。 diff --git a/problems/贪心算法总结篇.md b/problems/贪心算法总结篇.md index 413eb3ac..94e292ba 100644 --- a/problems/贪心算法总结篇.md +++ b/problems/贪心算法总结篇.md @@ -26,7 +26,7 @@ ## 贪心理论基础 -在贪心系列开篇词[关于贪心算法,你该了解这些!](https://mp.weixin.qq.com/s/O935TaoHE9Eexwe_vSbRAg)中,我们就讲解了大家对贪心的普遍疑惑。 +在贪心系列开篇词[关于贪心算法,你该了解这些!](https://programmercarl.com/贪心算法理论基础.html)中,我们就讲解了大家对贪心的普遍疑惑。 1. 贪心很简单,就是常识? @@ -48,42 +48,42 @@ Carl个人认为:如果找出局部最优并可以推出全局最优,就是 就像是 要用一下 1 + 1 = 2,没有必要再证明一下 1 + 1 究竟为什么等于 2。(例子极端了点,但是这个道理) -相信大家读完[关于贪心算法,你该了解这些!](https://mp.weixin.qq.com/s/O935TaoHE9Eexwe_vSbRAg),就对贪心有了一个基本的认识了。 +相信大家读完[关于贪心算法,你该了解这些!](https://programmercarl.com/贪心算法理论基础.html),就对贪心有了一个基本的认识了。 ## 贪心简单题 以下三道题目就是简单题,大家会发现贪心感觉就是常识。是的,如下三道题目,就是靠常识,但我都具体分析了局部最优是什么,全局最优是什么,贪心也要贪的有理有据! -* [贪心算法:分发饼干](https://mp.weixin.qq.com/s/YSuLIAYyRGlyxbp9BNC1uw) -* [贪心算法:K次取反后最大化的数组和](https://mp.weixin.qq.com/s/dMTzBBVllRm_Z0aaWvYazA) -* [贪心算法:柠檬水找零](https://mp.weixin.qq.com/s/0kT4P-hzY7H6Ae0kjQqnZg) +* [贪心算法:分发饼干](https://programmercarl.com/0455.分发饼干.html) +* [贪心算法:K次取反后最大化的数组和](https://programmercarl.com/1005.K次取反后最大化的数组和.html) +* [贪心算法:柠檬水找零](https://programmercarl.com/0860.柠檬水找零.html) ## 贪心中等题 贪心中等题,靠常识可能就有点想不出来了。开始初现贪心算法的难度与巧妙之处。 -* [贪心算法:摆动序列](https://mp.weixin.qq.com/s/Xytl05kX8LZZ1iWWqjMoHA) -* [贪心算法:单调递增的数字](https://mp.weixin.qq.com/s/TAKO9qPYiv6KdMlqNq_ncg) +* [贪心算法:摆动序列](https://programmercarl.com/0376.摆动序列.html) +* [贪心算法:单调递增的数字](https://programmercarl.com/0738.单调递增的数字.html) ### 贪心解决股票问题 大家都知道股票系列问题是动规的专长,其实用贪心也可以解决,而且还不止就这两道题目,但这两道比较典型,我就拿来单独说一说 -* [贪心算法:买卖股票的最佳时机II](https://mp.weixin.qq.com/s/VsTFA6U96l18Wntjcg3fcg) -* [贪心算法:买卖股票的最佳时机含手续费](https://mp.weixin.qq.com/s/olWrUuDEYw2Jx5rMeG7XAg) +* [贪心算法:买卖股票的最佳时机II](https://programmercarl.com/0122.买卖股票的最佳时机II.html) +* [贪心算法:买卖股票的最佳时机含手续费](https://programmercarl.com/0714.买卖股票的最佳时机含手续费.html) ### 两个维度权衡问题 在出现两个维度相互影响的情况时,两边一起考虑一定会顾此失彼,要先确定一个维度,再确定另一个一个维度。 -* [贪心算法:分发糖果](https://mp.weixin.qq.com/s/8MwlgFfvaNYmjGwjuMlETQ) -* [贪心算法:根据身高重建队列](https://mp.weixin.qq.com/s/-2TgZVdOwS-DvtbjjDEbfw) +* [贪心算法:分发糖果](https://programmercarl.com/0135.分发糖果.html) +* [贪心算法:根据身高重建队列](https://programmercarl.com/0406.根据身高重建队列.html) 在讲解本题的过程中,还强调了编程语言的重要性,模拟插队的时候,使用C++中的list(链表)替代了vector(动态数组),效率会高很多。 -所以在[贪心算法:根据身高重建队列(续集)](https://mp.weixin.qq.com/s/K-pRN0lzR-iZhoi-1FgbSQ)详细讲解了,为什么用list(链表)更快! +所以在[贪心算法:根据身高重建队列(续集)](https://programmercarl.com/根据身高重建队列(vector原理讲解).html)详细讲解了,为什么用list(链表)更快! **大家也要掌握自己所用的编程语言,理解其内部实现机制,这样才能写出高效的算法!** @@ -95,21 +95,20 @@ Carl个人认为:如果找出局部最优并可以推出全局最优,就是 关于区间问题,大家应该印象深刻,有一周我们专门讲解的区间问题,各种覆盖各种去重。 -* [贪心算法:跳跃游戏](https://mp.weixin.qq.com/s/606_N9j8ACKCODoCbV1lSA) -* [贪心算法:跳跃游戏II](https://mp.weixin.qq.com/s/kJBcsJ46DKCSjT19pxrNYg) -* [贪心算法:用最少数量的箭引爆气球](https://mp.weixin.qq.com/s/HxVAJ6INMfNKiGwI88-RFw) -* [贪心算法:无重叠区间](https://mp.weixin.qq.com/s/oFOEoW-13Bm4mik-aqAOmw) -* [贪心算法:划分字母区间](https://mp.weixin.qq.com/s/pdX4JwV1AOpc_m90EcO2Hw) -* [贪心算法:合并区间](https://mp.weixin.qq.com/s/royhzEM5tOkUFwUGrNStpw) +* [贪心算法:跳跃游戏](https://programmercarl.com/0055.跳跃游戏.html) +* [贪心算法:跳跃游戏II](https://programmercarl.com/0045.跳跃游戏II.html) +* [贪心算法:用最少数量的箭引爆气球](https://programmercarl.com/0452.用最少数量的箭引爆气球.html) +* [贪心算法:无重叠区间](https://programmercarl.com/0435.无重叠区间.html) +* [贪心算法:划分字母区间](https://programmercarl.com/0763.划分字母区间.html) +* [贪心算法:合并区间](https://programmercarl.com/0056.合并区间.html) ### 其他难题 -[贪心算法:最大子序和](https://mp.weixin.qq.com/s/DrjIQy6ouKbpletQr0g1Fg) 其实是动态规划的题目,但贪心性能更优,很多同学也是第一次发现贪心能比动规更优的题目。 +[贪心算法:最大子序和](https://programmercarl.com/0053.最大子序和.html) 其实是动态规划的题目,但贪心性能更优,很多同学也是第一次发现贪心能比动规更优的题目。 +[贪心算法:加油站](https://programmercarl.com/0134.加油站.html)可能以为是一道模拟题,但就算模拟其实也不简单,需要把while用的很娴熟。但其实是可以使用贪心给时间复杂度降低一个数量级。 -[贪心算法:加油站](https://mp.weixin.qq.com/s/aDbiNuEZIhy6YKgQXvKELw)可能以为是一道模拟题,但就算模拟其实也不简单,需要把while用的很娴熟。但其实是可以使用贪心给时间复杂度降低一个数量级。 - -最后贪心系列压轴题目[贪心算法:我要监控二叉树!](https://mp.weixin.qq.com/s/kCxlLLjWKaE6nifHC3UL2Q),不仅贪心的思路不好想,而且需要对二叉树的操作特别娴熟,这就是典型的交叉类难题了。 +最后贪心系列压轴题目[贪心算法:我要监控二叉树!](https://programmercarl.com/0968.监控二叉树.html),不仅贪心的思路不好想,而且需要对二叉树的操作特别娴熟,这就是典型的交叉类难题了。 ## 贪心每周总结 @@ -120,10 +119,10 @@ Carl个人认为:如果找出局部最优并可以推出全局最优,就是 所以周总结一定要看! -* [本周小结!(贪心算法系列一)](https://mp.weixin.qq.com/s/KQ2caT9GoVXgB1t2ExPncQ) -* [本周小结!(贪心算法系列二)](https://mp.weixin.qq.com/s/RiQri-4rP9abFmq_mlXNiQ) -* [本周小结!(贪心算法系列三)](https://mp.weixin.qq.com/s/JfeuK6KgmifscXdpEyIm-g) -* [本周小结!(贪心算法系列四)](https://mp.weixin.qq.com/s/zAMHT6JfB19ZSJNP713CAQ) +* [本周小结!(贪心算法系列一)](https://programmercarl.com/周总结/20201126贪心周末总结.html) +* [本周小结!(贪心算法系列二)](https://programmercarl.com/周总结/20201203贪心周末总结.html) +* [本周小结!(贪心算法系列三)](https://programmercarl.com/周总结/20201217贪心周末总结.html) +* [本周小结!(贪心算法系列四)](https://programmercarl.com/周总结/20201224贪心周末总结.html) ## 总结 diff --git a/problems/贪心算法理论基础.md b/problems/贪心算法理论基础.md index 77e8fe95..fdb7abf3 100644 --- a/problems/贪心算法理论基础.md +++ b/problems/贪心算法理论基础.md @@ -63,7 +63,7 @@ **那么刷题的时候什么时候真的需要数学推导呢?** -例如这道题目:[链表:环找到了,那入口呢?](https://mp.weixin.qq.com/s/_QVP3IkRZWx9zIpQRgajzA),这道题不用数学推导一下,就找不出环的起始位置,想试一下就不知道怎么试,这种题目确实需要数学简单推导一下。 +例如这道题目:[链表:环找到了,那入口呢?](https://programmercarl.com/0142.环形链表II.html),这道题不用数学推导一下,就找不出环的起始位置,想试一下就不知道怎么试,这种题目确实需要数学简单推导一下。 ## 贪心一般解题步骤 diff --git a/problems/链表总结篇.md b/problems/链表总结篇.md index 1f0de6fb..fed8cb60 100644 --- a/problems/链表总结篇.md +++ b/problems/链表总结篇.md @@ -10,7 +10,7 @@ ## 链表的理论基础 -在这篇文章[关于链表,你该了解这些!](https://mp.weixin.qq.com/s/fDGMmLrW7ZHlzkzlf_dZkw)中,介绍了如下几点: +在这篇文章[关于链表,你该了解这些!](https://programmercarl.com/链表理论基础.html)中,介绍了如下几点: * 链表的种类主要为:单链表,双链表,循环链表 * 链表的存储方式:链表的节点在内存中是分散存储的,通过指针连在一起。 @@ -23,17 +23,17 @@ ### 虚拟头结点 -在[链表:听说用虚拟头节点会方便很多?](https://mp.weixin.qq.com/s/L5aanfALdLEwVWGvyXPDqA)中,我们讲解了链表操作中一个非常总要的技巧:虚拟头节点。 +在[链表:听说用虚拟头节点会方便很多?](https://programmercarl.com/0203.移除链表元素.html)中,我们讲解了链表操作中一个非常总要的技巧:虚拟头节点。 链表的一大问题就是操作当前节点必须要找前一个节点才能操作。这就造成了,头结点的尴尬,因为头结点没有前一个节点了。 **每次对应头结点的情况都要单独处理,所以使用虚拟头结点的技巧,就可以解决这个问题**。 -在[链表:听说用虚拟头节点会方便很多?](https://mp.weixin.qq.com/s/L5aanfALdLEwVWGvyXPDqA)中,我给出了用虚拟头结点和没用虚拟头结点的代码,大家对比一下就会发现,使用虚拟头结点的好处。 +在[链表:听说用虚拟头节点会方便很多?](https://programmercarl.com/0203.移除链表元素.html)中,我给出了用虚拟头结点和没用虚拟头结点的代码,大家对比一下就会发现,使用虚拟头结点的好处。 ### 链表的基本操作 -在[链表:一道题目考察了常见的五个操作!](https://mp.weixin.qq.com/s/jnC_LAD0ZKCsj-FZc57F1g)中,我们通设计链表把链表常见的五个操作练习了一遍。 +在[链表:一道题目考察了常见的五个操作!](https://programmercarl.com/0707.设计链表.html)中,我们通设计链表把链表常见的五个操作练习了一遍。 这是练习链表基础操作的非常好的一道题目,考察了: @@ -49,13 +49,13 @@ ### 反转链表 -在[链表:听说过两天反转链表又写不出来了?](https://mp.weixin.qq.com/s/ckEvIVGcNLfrz6OLOMoT0A)中,讲解了如何反转链表。 +在[链表:听说过两天反转链表又写不出来了?](https://programmercarl.com/0206.翻转链表.html)中,讲解了如何反转链表。 因为反转链表的代码相对简单,有的同学可能直接背下来了,但一写还是容易出问题。 反转链表是面试中高频题目,很考察面试者对链表操作的熟练程度。 -我在[文章](https://mp.weixin.qq.com/s/ckEvIVGcNLfrz6OLOMoT0A)中,给出了两种反转的方式,迭代法和递归法。 +我在[文章](https://programmercarl.com/0206.翻转链表.html)中,给出了两种反转的方式,迭代法和递归法。 建议大家先学透迭代法,然后再看递归法,因为递归法比较绕,如果迭代还写不明白,递归基本也写不明白了。 @@ -63,16 +63,16 @@ ### 删除倒数第N个节点 -在[链表:删除链表倒数第N个节点,怎么删?](https://mp.weixin.qq.com/s/gxu65X1343xW_sBrkTz0Eg)中我们结合虚拟头结点 和 双指针法来移除链表倒数第N个节点。 +在[链表:删除链表倒数第N个节点,怎么删?](https://programmercarl.com/0019.删除链表的倒数第N个节点.html)中我们结合虚拟头结点 和 双指针法来移除链表倒数第N个节点。 ### 链表相交 -[链表:链表相交](https://mp.weixin.qq.com/s/BhfFfaGvt9Zs7UmH4YehZw)使用双指针来找到两个链表的交点(引用完全相同,即:内存地址完全相同的交点) +[链表:链表相交](https://programmercarl.com/面试题02.07.链表相交.html)使用双指针来找到两个链表的交点(引用完全相同,即:内存地址完全相同的交点) ## 环形链表 -在[链表:环找到了,那入口呢?](https://mp.weixin.qq.com/s/gt_VH3hQTqNxyWcl1ECSbQ)中,讲解了在链表如何找环,以及如何找环的入口位置。 +在[链表:环找到了,那入口呢?](https://programmercarl.com/0142.环形链表II.html)中,讲解了在链表如何找环,以及如何找环的入口位置。 这道题目可以说是链表的比较难的题目了。 但代码却十分简洁,主要在于一些数学证明。 @@ -80,15 +80,15 @@ 考察链表的操作其实就是考察指针的操作,是面试中的常见类型。 -链表篇中开头介绍[链表理论知识](https://mp.weixin.qq.com/s/slM1CH5Ew9XzK93YOQYSjA),然后分别通过经典题目介绍了如下知识点: +链表篇中开头介绍[链表理论知识](https://programmercarl.com/0203.移除链表元素.html),然后分别通过经典题目介绍了如下知识点: -1. [关于链表,你该了解这些!](https://mp.weixin.qq.com/s/fDGMmLrW7ZHlzkzlf_dZkw) -2. [虚拟头结点的技巧](https://mp.weixin.qq.com/s/L5aanfALdLEwVWGvyXPDqA) -3. [链表的增删改查](https://mp.weixin.qq.com/s/jnC_LAD0ZKCsj-FZc57F1g) -4. [反转一个链表](https://mp.weixin.qq.com/s/ckEvIVGcNLfrz6OLOMoT0A) -5. [删除倒数第N个节点](https://mp.weixin.qq.com/s/gxu65X1343xW_sBrkTz0Eg) -6. [链表相交](https://mp.weixin.qq.com/s/BhfFfaGvt9Zs7UmH4YehZw) -7. [有否环形,以及环的入口](https://mp.weixin.qq.com/s/gt_VH3hQTqNxyWcl1ECSbQ) +1. [关于链表,你该了解这些!](https://programmercarl.com/链表理论基础.html) +2. [虚拟头结点的技巧](https://programmercarl.com/0203.移除链表元素.html) +3. [链表的增删改查](https://programmercarl.com/0707.设计链表.html) +4. [反转一个链表](https://programmercarl.com/0206.翻转链表.html) +5. [删除倒数第N个节点](https://programmercarl.com/0019.删除链表的倒数第N个节点.html) +6. [链表相交](https://programmercarl.com/面试题02.07.链表相交.html) +7. [有否环形,以及环的入口](https://programmercarl.com/0142.环形链表II.html) diff --git a/problems/面试题02.07.链表相交.md b/problems/面试题02.07.链表相交.md index 8c3a5831..d59256c6 100644 --- a/problems/面试题02.07.链表相交.md +++ b/problems/面试题02.07.链表相交.md @@ -9,7 +9,7 @@ ## 面试题 02.07. 链表相交 -题目链接:https://leetcode-cn.com/problems/intersection-of-two-linked-lists-lcci/ +[力扣题目链接](https://leetcode-cn.com/problems/intersection-of-two-linked-lists-lcci/) 给定两个(单向)链表,判定它们是否相交并返回交点。请注意相交的定义基于节点的引用,而不是基于节点的值。换句话说,如果一个链表的第k个节点与另一个链表的第j个节点是同一节点(引用完全相同),则这两个链表相交。