diff --git a/README.md b/README.md index 017c4fdd..1108dac8 100644 --- a/README.md +++ b/README.md @@ -2,14 +2,14 @@ 👉 推荐 [在线阅读](http://programmercarl.com/) (Github在国内访问经常不稳定) 👉 推荐 [Gitee同步](https://gitee.com/programmercarl/leetcode-master) -> 1. **介绍**:本项目是一套完整的刷题计划,旨在帮助大家少走弯路,循序渐进学算法,[关注作者](#关于作者) +> 1. **介绍** :本项目是一套完整的刷题计划,旨在帮助大家少走弯路,循序渐进学算法,[关注作者](#关于作者) > 2. **正式出版** :[《代码随想录》](https://programmercarl.com/other/publish.html) 。 -> 3. **PDF版本** : [「代码随想录」算法精讲 PDF 版本](https://programmercarl.com/other/algo_pdf.html) 。 -> 4. **算法公开课** : [《代码随想录》算法视频公开课](https://www.bilibili.com/video/BV1fA4y1o715) 。 -> 5. **最强八股文:**:[代码随想录知识星球精华PDF](https://www.programmercarl.com/other/kstar_baguwen.html) -> 6. **刷题顺序** : README已经将刷题顺序排好了,按照顺序一道一道刷就可以。 -> 7. **学习社区** : 一起学习打卡/面试技巧/如何选择offer/大厂内推/职场规则/简历修改/技术分享/程序人生。欢迎加入[「代码随想录」知识星球](https://programmercarl.com/other/kstar.html) 。 -> 8. **提交代码**:本项目统一使用C++语言进行讲解,但已经有Java、Python、Go、JavaScript等等多语言版本,感谢[这里的每一位贡献者](https://github.com/youngyangyang04/leetcode-master/graphs/contributors),如果你也想贡献代码点亮你的头像,[点击这里](https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A)了解提交代码的方式。 +> 3. **PDF版本** :[「代码随想录」算法精讲 PDF 版本](https://programmercarl.com/other/algo_pdf.html) 。 +> 4. **算法公开课** :[《代码随想录》算法视频公开课](https://www.bilibili.com/video/BV1fA4y1o715) 。 +> 5. **最强八股文** :[代码随想录知识星球精华PDF](https://www.programmercarl.com/other/kstar_baguwen.html) 。 +> 6. **刷题顺序** :README已经将刷题顺序排好了,按照顺序一道一道刷就可以。 +> 7. **学习社区** :一起学习打卡/面试技巧/如何选择offer/大厂内推/职场规则/简历修改/技术分享/程序人生。欢迎加入[「代码随想录」知识星球](https://programmercarl.com/other/kstar.html) 。 +> 8. **提交代码** :本项目统一使用C++语言进行讲解,但已经有Java、Python、Go、JavaScript等等多语言版本,感谢[这里的每一位贡献者](https://github.com/youngyangyang04/leetcode-master/graphs/contributors),如果你也想贡献代码点亮你的头像,[点击这里](https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A)了解提交代码的方式。 > 9. **转载须知** :以下所有文章皆为我([程序员Carl](https://github.com/youngyangyang04))的原创。引用本项目文章请注明出处,发现恶意抄袭或搬运,会动用法律武器维护自己的权益。让我们一起维护一个良好的技术创作环境! diff --git a/problems/0035.搜索插入位置.md b/problems/0035.搜索插入位置.md index dd15b36b..4d9ee74f 100644 --- a/problems/0035.搜索插入位置.md +++ b/problems/0035.搜索插入位置.md @@ -250,23 +250,23 @@ public int searchInsert(int[] nums, int target) { -Golang: +### Golang -```golang +```go // 第一种二分法 func searchInsert(nums []int, target int) int { - l, r := 0, len(nums) - 1 - for l <= r{ - m := l + (r - l)/2 - if nums[m] == target{ - return m - }else if nums[m] > target{ - r = m - 1 - }else{ - l = m + 1 - } - } - return r + 1 + left, right := 0, len(nums)-1 + for left <= right { + mid := left + (right-left)/2 + if nums[mid] == target { + return mid + } else if nums[mid] > target { + right = mid - 1 + } else { + left = mid + 1 + } + } + return len(nums) } ``` diff --git a/problems/0059.螺旋矩阵II.md b/problems/0059.螺旋矩阵II.md index 78336d5a..d9a656b9 100644 --- a/problems/0059.螺旋矩阵II.md +++ b/problems/0059.螺旋矩阵II.md @@ -300,6 +300,61 @@ function generateMatrix(n: number): number[][] { Go: +```go +package main + +import "fmt" + +func main() { + n := 3 + fmt.Println(generateMatrix(n)) +} + +func generateMatrix(n int) [][]int { + startx, starty := 0, 0 + var loop int = n / 2 + var center int = n / 2 + count := 1 + offset := 1 + res := make([][]int, n) + for i := 0; i < n; i++ { + res[i] = make([]int, n) + } + for loop > 0 { + i, j := startx, starty + + //行数不变 列数在变 + for j = starty; j < n-offset; j++ { + res[startx][j] = count + count++ + } + //列数不变是j 行数变 + for i = startx; i < n-offset; i++ { + res[i][j] = count + count++ + } + //行数不变 i 列数变 j-- + for ; j > starty; j-- { + res[i][j] = count + count++ + } + //列不变 行变 + for ; i > startx; i-- { + res[i][j] = count + count++ + } + startx++ + starty++ + offset++ + loop-- + } + if n%2 == 1 { + res[center][center] = n * n + } + return res +} +``` + ```go func generateMatrix(n int) [][]int { top, bottom := 0, n-1 diff --git a/problems/0093.复原IP地址.md b/problems/0093.复原IP地址.md index a825b815..1f99a7a5 100644 --- a/problems/0093.复原IP地址.md +++ b/problems/0093.复原IP地址.md @@ -566,14 +566,24 @@ function restoreIpAddresses(s: string): string[] { ```Rust impl Solution { - fn is_valid(s: &Vec, start: usize, end: usize) -> bool { - if start > end { return false; } - if s[start] == '0' && start != end { return false; } + fn is_valid(s: &[char], start: usize, end: usize) -> bool { + if start > end { + return false; + } + if s[start] == '0' && start != end { + return false; + } let mut num = 0; - for i in start..=end { - if s[i] > '9' || s[i] < '0' { return false; } - if let Some(digit) = s[i].to_digit(10) { num = num * 10 + digit; } - if num > 255 { return false; } + for &c in s.iter().take(end + 1).skip(start) { + if !('0'..='9').contains(&c) { + return false; + } + if let Some(digit) = c.to_digit(10) { + num = num * 10 + digit; + } + if num > 255 { + return false; + } } true } diff --git a/problems/0189.旋转数组.md b/problems/0189.旋转数组.md index 8a7b0227..35819694 100644 --- a/problems/0189.旋转数组.md +++ b/problems/0189.旋转数组.md @@ -108,6 +108,7 @@ class Solution { ## Python +方法一:局部翻转 + 整体翻转 ```python class Solution: def rotate(self, A: List[int], k: int) -> None: @@ -123,6 +124,21 @@ class Solution: reverse(k, n - 1) ``` +方法二:利用余数 + +```python +class Solution: + def rotate(self, nums: List[int], k: int) -> None: + copy = nums[:] + + for i in range(len(nums)): + nums[(i + k) % len(nums)] = copy[i] + + return nums + + # 备注:这个方法会导致空间复杂度变成 O(n) 因为我们要创建一个 copy 数组。但是不失为一种思路。 +``` + ## Go ```go diff --git a/problems/0377-组合总和IV(完全背包的排列问题二维迭代理解).md b/problems/0377-组合总和IV(完全背包的排列问题二维迭代理解).md new file mode 100644 index 00000000..276329c5 --- /dev/null +++ b/problems/0377-组合总和IV(完全背包的排列问题二维迭代理解).md @@ -0,0 +1,145 @@ +# 完全背包的排列问题模拟 + +#### Problem + +1. 排列问题是完全背包中十分棘手的问题。 +2. 其在迭代过程中需要先迭代背包容量,再迭代物品个数,使得其在代码理解上较难入手。 + +#### Contribution + +本文档以力扣上[组合总和IV](https://leetcode.cn/problems/combination-sum-iv/)为例,提供一个二维dp的代码例子,并提供模拟过程以便于理解 + +#### Code + +```cpp +int combinationSum4(vector& nums, int target) { + // 定义背包容量为target,物品个数为nums.size()的dp数组 + // dp[i][j]表示将第0-i个物品添加入排列中,和为j的排列方式 + vector> dp (nums.size(), vector(target+1,0)); + + // 表示有0,1,...,n个物品可选择的情况下,和为0的选择方法为1:什么都不取 + for(int i = 0; i < nums.size(); i++) dp[i][0] = 1; + + // 必须按列遍历,因为右边数组需要知道左边数组最低部的信息(排列问题) + // 后面的模拟可以更清楚的表现这么操作的原因 + for(int i = 1; i <= target; i++){ + for(int j = 0; j < nums.size(); j++){ + // 只有nums[j]可以取的情况 + if(j == 0){ + if(nums[j] > i) dp[j][i] = 0; + // 如果背包容量放不下 那么此时没有排列方式 + else dp[j][i] = dp[nums.size()-1][i-nums[j]]; + // 如果背包容量放的下 全排列方式为dp[最底层][容量-该物品容量]排列方式后面放一个nums[j] + } + // 有多个nums数可以取 + else{ + // 如果背包容量放不下 那么沿用0-j-1个物品的排列方式 + if(nums[j] > i) dp[j][i] = dp[j-1][i]; + // 如果背包容量放得下 在dp[最底层][容量-该物品容量]排列方式后面放一个nums[j]后面放个nums[j] + // INT_MAX避免溢出 + else if(i >= nums[j] && dp[j-1][i] < INT_MAX - dp[nums.size()-1][i-nums[j]]) + dp[j][i] = dp[j-1][i] + dp[nums.size()-1][i-nums[j]]; + } + } + } + // 打印dp数组 + for(int i = 0; i < nums.size(); i++){ + for(int j = 0; j <= target; j++){ + cout< list.Size { + return -1 + } + // 让cur等于真正头节点 + cur := list.dummyHead.Next + for i := 0; i < index; i++ { + cur = cur.Next + } + return cur.Val +} + +// 在链表最前面插入一个节点 +func (list *SingleLinkedList) addAtHead(val int) { + // 以下两行代码可用一行代替 + // newNode := new(SingleNode) + // newNode.Val = val + newNode := &SingleNode{Val: val} + + newNode.Next = list.dummyHead.Next + list.dummyHead.Next = newNode + list.Size++ +} + +// 在链表最后面插入一个节点 +func (list *SingleLinkedList) addAtTail(val int) { + newNode := &SingleNode{Val: val} + cur := list.dummyHead + for cur.Next != nil { + cur = cur.Next + } + cur.Next = newNode + list.Size++ +} + +// 打印链表 +func (list *SingleLinkedList) printLinkedList() { + cur := list.dummyHead + for cur.Next != nil { + fmt.Println(cur.Next.Val) + cur = cur.Next + } +} + +// 在第index个节点之前插入新节点 +func (list *SingleLinkedList) addAtIndex(index int, val int) { + if index < 0 { + index = 0 + } else if index > list.Size { + return + } + + newNode := &SingleNode{Val: val} + cur := list.dummyHead //用虚拟头节点不用考虑在头部插入的情况 + for i := 0; i < index; i++ { + cur = cur.Next + } + newNode.Next = cur.Next + cur.Next = newNode + list.Size++ +} + +``` + ```go //循环双链表 type MyLinkedList struct { diff --git a/problems/0763.划分字母区间.md b/problems/0763.划分字母区间.md index 6c4f1c5e..6667e740 100644 --- a/problems/0763.划分字母区间.md +++ b/problems/0763.划分字母区间.md @@ -276,6 +276,33 @@ class Solution: # 最右侧区间(字符串长度为1时的特殊情况也包含于其中) res.append(right - left + 1) return res + +# 解法三:区间合并法 (结合下一题 56. Merge Intervals 的写法) +class Solution: # + def partitionLabels(self, s: str) -> List[int]: + aaa = list(set(s)) + #aaa.sort() + bbb = list(s) + ccc = [] + for i in reversed(bbb): + ccc.append(i) + intervals = [] + for i in range(len(aaa)): + intervals.append([bbb.index(aaa[i]),len(bbb)-ccc.index(aaa[i])-1]) + # 先求出各个字母的存在区间,之后利用区间合并方法得出所有不相邻的最大区间。 + intervals.sort(key = lambda x:x[0]) + newinterval = [] + left, right = intervals[0][0], intervals[0][1] + for i in range(1,len(intervals)): + if intervals[i][0] in range(left, right+1): + right = max(intervals[i][1],intervals[i-1][1],right) + left = min(intervals[i-1][0],left) + else: + newinterval.append(right-left+1) + left = intervals[i][0] + right = intervals[i][1] + newinterval.append(right-left+1) + return newinterval ``` ### Go