mirror of
https://github.com/youngyangyang04/leetcode-master.git
synced 2025-07-10 12:15:58 +08:00
Merge branch 'master' of github.com:youngyangyang04/leetcode-master
This commit is contained in:
14
README.md
14
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))的原创。引用本项目文章请注明出处,发现恶意抄袭或搬运,会动用法律武器维护自己的权益。让我们一起维护一个良好的技术创作环境!
|
||||
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
145
problems/0377-组合总和IV(完全背包的排列问题二维迭代理解).md
Normal file
145
problems/0377-组合总和IV(完全背包的排列问题二维迭代理解).md
Normal 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}。
|
||||
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
Reference in New Issue
Block a user