Merge branch 'master' of github.com:youngyangyang04/leetcode-master

This commit is contained in:
programmercarl
2023-02-22 17:21:52 +08:00
8 changed files with 381 additions and 28 deletions

View File

@ -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))的原创。引用本项目文章请注明出处,发现恶意抄袭或搬运,会动用法律武器维护自己的权益。让我们一起维护一个良好的技术创作环境!

View File

@ -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
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 r + 1
return len(nums)
}
```

View File

@ -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

View File

@ -566,14 +566,24 @@ function restoreIpAddresses(s: string): string[] {
```Rust
impl Solution {
fn is_valid(s: &Vec<char>, 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
}

View File

@ -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

View File

@ -0,0 +1,145 @@
# 完全背包的排列问题模拟
#### Problem
1. 排列问题是完全背包中十分棘手的问题。
2. 其在迭代过程中需要先迭代背包容量,再迭代物品个数,使得其在代码理解上较难入手。
#### Contribution
本文档以力扣上[组合总和IV](https://leetcode.cn/problems/combination-sum-iv/)为例提供一个二维dp的代码例子并提供模拟过程以便于理解
#### Code
```cpp
int combinationSum4(vector<int>& nums, int target) {
// 定义背包容量为target物品个数为nums.size()的dp数组
// dp[i][j]表示将第0-i个物品添加入排列中和为j的排列方式
vector<vector<int>> 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<<dp[i][j]<<" ";
}
cout<<endl;
}
return dp[nums.size()-1][target];
}
```
#### Simulation
##### 样例 nums = [2,3,4], target = 6
##### 1. 初始化一个3x7的dp数组
1 0 0 0 0 0 0
1 0 0 0 0 0 0
1 0 0 0 0 0 0
dp\[0-2\]\[0\] = 1含义是有nums[0-2]物品时使得背包容量为0的取法为1作用是在取到nums[i]物品使得背包容量为nums[i]时取法为1。
##### 2.迭代方式
必须列优先,因为右边的数组在迭代时需要最左下的数组最终结果。
##### 3. 模拟过程
i = 1, j = 0 dp\[0\]\[1\] = 0表示在物品集合{2}中无法组成和为1
i = 1, j = 1 dp\[1\]\[1\] = 0表示在物品集合{2,3}中无法组成和为1
i = 1, j = 2 dp\[2\]\[1\] = 0表示在物品集合{2,3,4}中无法组成和为1
1 0 0 0 0 0 0
1 0 0 0 0 0 0
1 **0** 0 0 0 0 0
此时dp\[2\]\[1\]作为第1列最底部的元素表示所有物品都有的情况下组成和为1的排列方式为0
————————————————————————————
i = 2, j = 0 dp\[0\]\[2\] = 1表示在物品集合{2}中取出和为2的排列有{2}
i = 2, j = 1 dp\[1\]\[2\] = 1表示在物品集合{2,3}中取出和为2的排列有{2}
i = 2, j = 2 dp\[2\]\[2\] = 1表示在物品集合{2,3,4}中取出和为2的排列有{2}
1 0 1 0 0 0 0
1 0 1 0 0 0 0
1 0 **1** 0 0 0 0
此时dp\[2\]\[2\]作为第2列最底部的元素表示所有物品都有的情况下和为2的排列方式有1个 类比成一维dp即dp[2]=dp[0]
————————————————————————————
i = 3, j = 0 dp\[0\]\[3\] = 0表示在物品集合{2}中无法取出和为3
i = 3, j = 1 dp\[1\]\[3\] = 1表示在物品集合{2,3}中取出和为3的排列有{3}
i = 3, j = 2 dp\[2\]\[3\] = 1表示在物品集合{2,3,4}中取出和为3的排列有{3}
1 0 1 0 0 0 0
1 0 1 1 0 0 0
1 0 1 **1** 0 0 0
此时dp\[2\]\[3\]作为第3列最底部的元素表示所有物品都有的情况下和为3的排列方式有1个类比成一维dp即dp[3]=dp[0]
————————————————————————————
i = 4, j = 0 dp\[0\]\[4\] = 1表示在物品集合{2}中取出和为4的排列有在原有的排列{2}后添加一个2成为{2,2}从第2列底部信息继承获得
i = 4, j = 1 dp\[1\]\[4\] = 1表示在物品集合{2,3}中取出和为4的排列有{2,2}
i = 4, j = 2 dp\[2\]\[4\] = 2表示在物品集合{2,3,4}中取出和为4的排列有{{2,2},{4}}{2,2}的信息从该列头上获得)
1 0 1 0 1 0 0
1 0 1 1 1 0 0
1 0 1 1 **2** 0 0
此时dp\[2\]\[4\]作为第4列最底部的元素表示所有物品都有的情况下和为4的排列方式有2个
————————————————————————————
i = 5, j = 0 dp\[0\]\[5\] = 1表示在物品集合{2}中取出和为5的排列有{3,2} **(3的信息由dp[2]\[3]获得即将2放在3的右边)**
i = 5, j = 1 dp\[1\]\[5\] = 2表示在物品集合{2,3}中取出和为5的排列有{{2,3},{3,2}} **({3,2}由上一行信息继承,{2,3}是从dp[2] [2]获得将3放在2的右边)**
i = 5, j = 2 dp\[2\]\[5\] = 2表示在物品集合{2,3,4}中取出和为5的排列有{{2,3},{3,2}}
1 0 1 0 1 1 0
1 0 1 1 1 2 0
1 0 1 1 2 **2** 0
此时dp\[2\]\[5\]作为第5列最底部的元素表示所有物品都有的情况下和为5的排列方式有2个
————————————————————————————
i = 6, j = 0 dp\[0\]\[6\] = 2表示在物品集合{2}中取出和为6的排列有{{2,2,2},{4,2}} **(信息由dp[2]\[4]获得即将2放在{2,2}和{4}的右边)**
i = 6, j = 1 dp\[1\]\[6\] = 3表示在物品集合{2,3}中取出和为6的排列有{{2,2,2},{4,2},{3,3}} **({2,2,2},{4,2}由上一行信息继承,{3,3}是从dp[2] [3]获得将3放在3的右边)**
i = 6, j = 2 dp\[2\]\[6\] = 4表示在物品集合{2,3,4}中取出和为6的排列有{{2,2,2},{4,2},{3,3},{2,4}} **({2,2,2},{4,2},{3,3}由上一行继承,{2,4}从dp[2]获得将4放在2的右边)**
1 0 1 0 1 1 2
1 0 1 1 1 2 3
1 0 1 1 2 2 **4**
此时dp\[2\]\[6\]作为第6列最底部的元素表示所有物品都有的情况下和为6的排列方式有4个为{2,2,2}{4,2}{3,3}{2,4}。

View File

@ -652,6 +652,106 @@ class MyLinkedList:
Go
```go
//单链表实现
package main
import "fmt"
func main() {
var list = new(SingleLinkedList)
list.Init()
list.addAtHead(100)
list.addAtTail(242)
list.addAtTail(777)
list.addAtIndex(1, 99999)
list.printLinkedList()
}
// 单链表写法 //
type SingleNode struct {
Val int
Next *SingleNode
}
type SingleLinkedList struct {
dummyHead *SingleNode
Size int
}
// 初始化链表
func (list *SingleLinkedList) Init() *SingleLinkedList {
list.Size = 0
list.dummyHead = new(SingleNode)
return list
}
// 获取第index个节点数值
func (list *SingleLinkedList) get(index int) int {
if list != nil || index < 0 || index > 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 {

View File

@ -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