Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: update solutions to lc problems: No.39~42 #2469

Merged
merged 1 commit into from
Mar 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions solution/0000-0099/0039.Combination Sum/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,16 +52,14 @@

## 解法

### 方法一:排序 + 剪枝 + 回溯(两种写法)
### 方法一:排序 + 剪枝 + 回溯

我们可以先对数组进行排序,方便剪枝。

接下来,我们设计一个函数 $dfs(i, s)$,表示从下标 $i$ 开始搜索,且剩余目标值为 $s$,其中 $i$ 和 $s$ 都是非负整数,当前搜索路径为 $t$,答案为 $ans$。

在函数 $dfs(i, s)$ 中,我们先判断 $s$ 是否为 $0$,如果是,则将当前搜索路径 $t$ 加入答案 $ans$ 中,然后返回。如果 $s \lt candidates[i]$,说明当前下标及后面的下标的元素都大于剩余目标值 $s$,路径不合法,直接返回。否则,我们从下标 $i$ 开始搜索,搜索的下标范围是 $j \in [i, n)$,其中 $n$ 为数组 $candidates$ 的长度。在搜索的过程中,我们将当前下标的元素加入搜索路径 $t$,递归调用函数 $dfs(j, s - candidates[j])$,递归结束后,将当前下标的元素从搜索路径 $t$ 中移除。

我们也可以将函数 $dfs(i, s)$ 的实现逻辑改为另一种写法。在函数 $dfs(i, s)$ 中,我们先判断 $s$ 是否为 $0$,如果是,则将当前搜索路径 $t$ 加入答案 $ans$ 中,然后返回。如果 $i \geq n$ 或者 $s \lt candidates[i]$,路径不合法,直接返回。否则,我们考虑两种情况,一种是不选当前下标的元素,即递归调用函数 $dfs(i + 1, s)$,另一种是选当前下标的元素,即递归调用函数 $dfs(i, s - candidates[i])$。

在主函数中,我们只要调用函数 $dfs(0, target)$,即可得到答案。

时间复杂度 $O(2^n \times n)$,空间复杂度 $O(n)$。其中 $n$ 为数组 $candidates$ 的长度。由于剪枝,实际的时间复杂度要远小于 $O(2^n \times n)$。
Expand Down Expand Up @@ -258,7 +256,11 @@ public class Solution {

<!-- tabs:end -->

### 方法二
### 方法二:排序 + 剪枝 + 回溯(写法二)

我们也可以将函数 $dfs(i, s)$ 的实现逻辑改为另一种写法。在函数 $dfs(i, s)$ 中,我们先判断 $s$ 是否为 $0$,如果是,则将当前搜索路径 $t$ 加入答案 $ans$ 中,然后返回。如果 $i \geq n$ 或者 $s \lt candidates[i]$,路径不合法,直接返回。否则,我们考虑两种情况,一种是不选当前下标的元素,即递归调用函数 $dfs(i + 1, s)$,另一种是选当前下标的元素,即递归调用函数 $dfs(i, s - candidates[i])$。

时间复杂度 $O(2^n \times n)$,空间复杂度 $O(n)$。其中 $n$ 为数组 $candidates$ 的长度。由于剪枝,实际的时间复杂度要远小于 $O(2^n \times n)$。

<!-- tabs:start -->

Expand Down
10 changes: 6 additions & 4 deletions solution/0000-0099/0039.Combination Sum/README_EN.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,16 +50,14 @@ These are the only two combinations.

## Solutions

### Solution 1: Sorting + Pruning + Backtracking (Two Implementations)
### Solution 1: Sorting + Pruning + Backtracking

We can first sort the array to facilitate pruning.

Next, we design a function $dfs(i, s)$, which means starting the search from index $i$ with a remaining target value of $s$. Here, $i$ and $s$ are both non-negative integers, the current search path is $t$, and the answer is $ans$.

In the function $dfs(i, s)$, we first check whether $s$ is $0$. If it is, we add the current search path $t$ to the answer $ans$, and then return. If $s \lt candidates[i]$, it means that the elements of the current index and the following indices are all greater than the remaining target value $s$, and the path is invalid, so we return directly. Otherwise, we start the search from index $i$, and the search index range is $j \in [i, n)$, where $n$ is the length of the array $candidates$. During the search, we add the element of the current index to the search path $t$, recursively call the function $dfs(j, s - candidates[j])$, and after the recursion ends, we remove the element of the current index from the search path $t$.

We can also change the implementation logic of the function $dfs(i, s)$ to another form. In the function $dfs(i, s)$, we first check whether $s$ is $0$. If it is, we add the current search path $t$ to the answer $ans$, and then return. If $i \geq n$ or $s \lt candidates[i]$, the path is invalid, so we return directly. Otherwise, we consider two situations, one is not selecting the element of the current index, that is, recursively calling the function $dfs(i + 1, s)$, and the other is selecting the element of the current index, that is, recursively calling the function $dfs(i, s - candidates[i])$.

In the main function, we just need to call the function $dfs(0, target)$ to get the answer.

The time complexity is $O(2^n \times n)$, and the space complexity is $O(n)$. Here, $n$ is the length of the array $candidates$. Due to pruning, the actual time complexity is much less than $O(2^n \times n)$.
Expand Down Expand Up @@ -256,7 +254,11 @@ public class Solution {

<!-- tabs:end -->

### Solution 2
### Solution 2: Sorting + Pruning + Backtracking(Another Form)

We can also change the implementation logic of the function $dfs(i, s)$ to another form. In the function $dfs(i, s)$, we first check whether $s$ is $0$. If it is, we add the current search path $t$ to the answer $ans$, and then return. If $i \geq n$ or $s \lt candidates[i]$, the path is invalid, so we return directly. Otherwise, we consider two situations, one is not selecting the element of the current index, that is, recursively calling the function $dfs(i + 1, s)$, and the other is selecting the element of the current index, that is, recursively calling the function $dfs(i, s - candidates[i])$.

The time complexity is $O(2^n \times n)$, and the space complexity is $O(n)$. Here, $n$ is the length of the array $candidates$. Due to pruning, the actual time complexity is much less than $O(2^n \times n)$.

<!-- tabs:start -->

Expand Down
10 changes: 6 additions & 4 deletions solution/0000-0099/0040.Combination Sum II/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,16 +50,14 @@

## 解法

### 方法一:排序 + 剪枝 + 回溯(两种写法)
### 方法一:排序 + 剪枝 + 回溯

我们可以先对数组进行排序,方便剪枝以及跳过重复的数字。

接下来,我们设计一个函数 $dfs(i, s)$,表示从下标 $i$ 开始搜索,且剩余目标值为 $s$,其中 $i$ 和 $s$ 都是非负整数,当前搜索路径为 $t$,答案为 $ans$。

在函数 $dfs(i, s)$ 中,我们先判断 $s$ 是否为 $0$,如果是,则将当前搜索路径 $t$ 加入答案 $ans$ 中,然后返回。如果 $i \geq n$,或者 $s \lt candidates[i]$,说明当前路径不合法,直接返回。否则,我们从下标 $i$ 开始搜索,搜索的下标范围是 $j \in [i, n)$,其中 $n$ 为数组 $candidates$ 的长度。在搜索的过程中,如果 $j \gt i$ 并且 $candidates[j] = candidates[j - 1]$,说明当前数字与上一个数字相同,我们可以跳过当前数字,因为上一个数字已经搜索过了。否则,我们将当前数字加入搜索路径 $t$ 中,然后递归调用函数 $dfs(j + 1, s - candidates[j])$,然后将当前数字从搜索路径 $t$ 中移除。

我们也可以将函数 $dfs(i, s)$ 的实现逻辑改为另一种写法。如果我们选择当前数字,那么我们将当前数字加入搜索路径 $t$ 中,然后递归调用函数 $dfs(i + 1, s - candidates[i])$,然后将当前数字从搜索路径 $t$ 中移除。如果我们不选择当前数字,那么我们可以跳过与当前数字相同的所有数字,然后递归调用函数 $dfs(j, s)$,其中 $j$ 为第一个与当前数字不同的数字的下标。

在主函数中,我们只要调用函数 $dfs(0, target)$,即可得到答案。

时间复杂度 $O(2^n \times n)$,空间复杂度 $O(n)$。其中 $n$ 为数组 $candidates$ 的长度。由于剪枝,实际的时间复杂度要远小于 $O(2^n \times n)$。
Expand Down Expand Up @@ -310,7 +308,11 @@ public class Solution {

<!-- tabs:end -->

### 方法二
### 方法二:排序 + 剪枝 + 回溯(写法二)

我们也可以将函数 $dfs(i, s)$ 的实现逻辑改为另一种写法。如果我们选择当前数字,那么我们将当前数字加入搜索路径 $t$ 中,然后递归调用函数 $dfs(i + 1, s - candidates[i])$,然后将当前数字从搜索路径 $t$ 中移除。如果我们不选择当前数字,那么我们可以跳过与当前数字相同的所有数字,然后递归调用函数 $dfs(j, s)$,其中 $j$ 为第一个与当前数字不同的数字的下标。

时间复杂度 $O(2^n \times n)$,空间复杂度 $O(n)$。其中 $n$ 为数组 $candidates$ 的长度。由于剪枝,实际的时间复杂度要远小于 $O(2^n \times n)$。

<!-- tabs:start -->

Expand Down
8 changes: 6 additions & 2 deletions solution/0000-0099/0040.Combination Sum II/README_EN.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@

## Solutions

### Solution 1: Sorting + Pruning + Backtracking (Two Implementations)
### Solution 1: Sorting + Pruning + Backtracking

We can first sort the array to facilitate pruning and skipping duplicate numbers.

Expand Down Expand Up @@ -306,7 +306,11 @@ public class Solution {

<!-- tabs:end -->

### Solution 2
### Solution 2: Sorting + Pruning + Backtracking(Another Form)

We can also change the implementation logic of the function $dfs(i, s)$ to another form. If we choose the current number, we add the current number to the search path $t$, then recursively call the function $dfs(i + 1, s - candidates[i])$, and after the recursion ends, we remove the current number from the search path $t$. If we do not choose the current number, we can skip all numbers that are the same as the current number, then recursively call the function $dfs(j, s)$, where $j$ is the index of the first number that is different from the current number.

The time complexity is $O(2^n \times n)$, and the space complexity is $O(n)$. Here, $n$ is the length of the array $candidates$. Due to pruning, the actual time complexity is much less than $O(2^n \times n)$.

<!-- tabs:start -->

Expand Down
83 changes: 25 additions & 58 deletions solution/0000-0099/0041.First Missing Positive/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -178,80 +178,47 @@ impl Solution {
```cs
public class Solution {
public int FirstMissingPositive(int[] nums) {
var i = 0;
while (i < nums.Length)
{
if (nums[i] > 0 && nums[i] <= nums.Length)
{
var index = nums[i] -1;
if (index != i && nums[index] != nums[i])
{
var temp = nums[i];
nums[i] = nums[index];
nums[index] = temp;
}
else
{
++i;
}
}
else
{
++i;
int n = nums.Length;
for (int i = 0; i < n; ++i) {
while (nums[i] >= 1 && nums[i] <= n && nums[i] != nums[nums[i] - 1]) {
Swap(nums, i, nums[i] - 1);
}
}

for (i = 0; i < nums.Length; ++i)
{
if (nums[i] != i + 1)
{
for (int i = 0; i < n; ++i) {
if (i + 1 != nums[i]) {
return i + 1;
}
}
return nums.Length + 1;
return n + 1;
}

private void Swap(int[] nums, int i, int j) {
int t = nums[i];
nums[i] = nums[j];
nums[j] = t;
}
}
```

```c
int firstMissingPositive(int* nums, int numsSize) {

int Max = nums[0], i, *Count;

for (i = 1; i < numsSize; i++) {
Max = (Max < nums[i]) ? nums[i] : Max;
}

Count = (int*) calloc(Max + 1, sizeof(int));
for (i = 0; i < numsSize; i++) {
if (nums[i] > 0) {
Count[nums[i]]++;
for (int i = 0; i < numsSize; ++i) {
while (nums[i] >= 1 && nums[i] <= numsSize && nums[i] != nums[nums[i] - 1]) {
swap(&nums[i], &nums[nums[i] - 1]);
}
}

i = 1;
while (Count[i] != 0) {
i++;
for (int i = 0; i < numsSize; ++i) {
if (i + 1 != nums[i]) {
return i + 1;
}
}

return i;
return numsSize + 1;
}
```

<!-- tabs:end -->

### 方法二

<!-- tabs:start -->

```ts
function firstMissingPositive(nums: number[]): number {
const set = new Set(nums);
let ans = 1;
while (true) {
if (!set.has(ans)) return ans;
ans++;
}
void swap(int* a, int* b) {
int t = *a;
*a = *b;
*b = t;
}
```

Expand Down
83 changes: 25 additions & 58 deletions solution/0000-0099/0041.First Missing Positive/README_EN.md
Original file line number Diff line number Diff line change
Expand Up @@ -178,80 +178,47 @@ impl Solution {
```cs
public class Solution {
public int FirstMissingPositive(int[] nums) {
var i = 0;
while (i < nums.Length)
{
if (nums[i] > 0 && nums[i] <= nums.Length)
{
var index = nums[i] -1;
if (index != i && nums[index] != nums[i])
{
var temp = nums[i];
nums[i] = nums[index];
nums[index] = temp;
}
else
{
++i;
}
}
else
{
++i;
int n = nums.Length;
for (int i = 0; i < n; ++i) {
while (nums[i] >= 1 && nums[i] <= n && nums[i] != nums[nums[i] - 1]) {
Swap(nums, i, nums[i] - 1);
}
}

for (i = 0; i < nums.Length; ++i)
{
if (nums[i] != i + 1)
{
for (int i = 0; i < n; ++i) {
if (i + 1 != nums[i]) {
return i + 1;
}
}
return nums.Length + 1;
return n + 1;
}

private void Swap(int[] nums, int i, int j) {
int t = nums[i];
nums[i] = nums[j];
nums[j] = t;
}
}
```

```c
int firstMissingPositive(int* nums, int numsSize) {

int Max = nums[0], i, *Count;

for (i = 1; i < numsSize; i++) {
Max = (Max < nums[i]) ? nums[i] : Max;
}

Count = (int*) calloc(Max + 1, sizeof(int));
for (i = 0; i < numsSize; i++) {
if (nums[i] > 0) {
Count[nums[i]]++;
for (int i = 0; i < numsSize; ++i) {
while (nums[i] >= 1 && nums[i] <= numsSize && nums[i] != nums[nums[i] - 1]) {
swap(&nums[i], &nums[nums[i] - 1]);
}
}

i = 1;
while (Count[i] != 0) {
i++;
for (int i = 0; i < numsSize; ++i) {
if (i + 1 != nums[i]) {
return i + 1;
}
}

return i;
return numsSize + 1;
}
```

<!-- tabs:end -->

### Solution 2

<!-- tabs:start -->

```ts
function firstMissingPositive(nums: number[]): number {
const set = new Set(nums);
let ans = 1;
while (true) {
if (!set.has(ans)) return ans;
ans++;
}
void swap(int* a, int* b) {
int t = *a;
*a = *b;
*b = t;
}
```

Expand Down
29 changes: 13 additions & 16 deletions solution/0000-0099/0041.First Missing Positive/Solution.c
Original file line number Diff line number Diff line change
@@ -1,22 +1,19 @@
int firstMissingPositive(int* nums, int numsSize) {

int Max = nums[0], i, *Count;

for (i = 1; i < numsSize; i++) {
Max = (Max < nums[i]) ? nums[i] : Max;
}

Count = (int*) calloc(Max + 1, sizeof(int));
for (i = 0; i < numsSize; i++) {
if (nums[i] > 0) {
Count[nums[i]]++;
for (int i = 0; i < numsSize; ++i) {
while (nums[i] >= 1 && nums[i] <= numsSize && nums[i] != nums[nums[i] - 1]) {
swap(&nums[i], &nums[nums[i] - 1]);
}
}

i = 1;
while (Count[i] != 0) {
i++;
for (int i = 0; i < numsSize; ++i) {
if (i + 1 != nums[i]) {
return i + 1;
}
}
return numsSize + 1;
}

return i;
void swap(int* a, int* b) {
int t = *a;
*a = *b;
*b = t;
}
Loading
Loading