Skip to content

Commit

Permalink
feat: add solutions to lc problem: No.0047 (#4031)
Browse files Browse the repository at this point in the history
  • Loading branch information
yanglbme authored Feb 6, 2025
1 parent 0aa2781 commit 59cb267
Show file tree
Hide file tree
Showing 7 changed files with 200 additions and 82 deletions.
95 changes: 68 additions & 27 deletions solution/0000-0099/0047.Permutations II/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,12 @@ tags:

我们可以先对数组进行排序,这样就可以将重复的数字放在一起,方便我们进行去重。

然后,我们设计一个函数 $dfs(i)$,表示当前需要填写第 $i$ 个位置的数。函数的具体实现如下:
然后,我们设计一个函数 $\textit{dfs}(i)$,表示当前需要填写第 $i$ 个位置的数。函数的具体实现如下:

- 如果 $i = n$,说明我们已经填写完毕,将当前排列加入答案数组中,然后返回。
- 否则,我们枚举第 $i$ 个位置的数 $nums[j]$,其中 $j$ 的范围是 $[0, n - 1]$。我们需要保证 $nums[j]$ 没有被使用过,并且与前面枚举的数不同,这样才能保证当前排列不重复。如果满足条件,我们就可以填写 $nums[j]$,并继续递归地填写下一个位置,即调用 $dfs(i + 1)$。在递归调用结束后,我们需要将 $nums[j]$ 标记为未使用,以便于进行后面的枚举。
- 否则,我们枚举第 $i$ 个位置的数 $nums[j]$,其中 $j$ 的范围是 $[0, n - 1]$。我们需要保证 $nums[j]$ 没有被使用过,并且与前面枚举的数不同,这样才能保证当前排列不重复。如果满足条件,我们就可以填写 $nums[j]$,并继续递归地填写下一个位置,即调用 $\textit{dfs}(i + 1)$。在递归调用结束后,我们需要将 $nums[j]$ 标记为未使用,以便于进行后面的枚举。

在主函数中,我们首先对数组进行排序,然后调用 $dfs(0)$,即从第 0 个位置开始填写,最终返回答案数组即可。
在主函数中,我们首先对数组进行排序,然后调用 $\textit{dfs}(0)$,即从第 0 个位置开始填写,最终返回答案数组即可。

时间复杂度 $O(n \times n!)$,空间复杂度 $O(n)$。其中 $n$ 是数组的长度。需要进行 $n!$ 次枚举,每次枚举需要 $O(n)$ 的时间来判断是否重复。另外,我们需要一个标记数组来标记每个位置是否被使用过,因此空间复杂度为 $O(n)$。

Expand Down Expand Up @@ -141,12 +141,12 @@ class Solution {
class Solution {
public:
vector<vector<int>> permuteUnique(vector<int>& nums) {
sort(nums.begin(), nums.end());
ranges::sort(nums);
int n = nums.size();
vector<vector<int>> ans;
vector<int> t(n);
vector<bool> vis(n);
function<void(int)> dfs = [&](int i) {
auto dfs = [&](this auto&& dfs, int i) {
if (i == n) {
ans.emplace_back(t);
return;
Expand All @@ -171,7 +171,7 @@ public:
```go
func permuteUnique(nums []int) (ans [][]int) {
sort.Ints(nums)
slices.Sort(nums)
n := len(nums)
t := make([]int, n)
vis := make([]bool, n)
Expand Down Expand Up @@ -203,8 +203,8 @@ function permuteUnique(nums: number[]): number[][] {
nums.sort((a, b) => a - b);
const n = nums.length;
const ans: number[][] = [];
const t: number[] = new Array(n);
const vis: boolean[] = new Array(n);
const t: number[] = Array(n);
const vis: boolean[] = Array(n).fill(false);
const dfs = (i: number) => {
if (i === n) {
ans.push(t.slice());
Expand All @@ -228,34 +228,75 @@ function permuteUnique(nums: number[]): number[][] {
#### Rust

```rust
use std::collections::HashSet;
impl Solution {
fn dfs(i: usize, nums: &mut Vec<i32>, res: &mut Vec<Vec<i32>>) {
pub fn permute_unique(mut nums: Vec<i32>) -> Vec<Vec<i32>> {
nums.sort();
let n = nums.len();
if i == n {
res.push(nums.clone());
return;
}
let mut set = HashSet::new();
for j in i..n {
if set.contains(&nums[j]) {
continue;
let mut ans = Vec::new();
let mut t = vec![0; n];
let mut vis = vec![false; n];

fn dfs(
nums: &Vec<i32>,
t: &mut Vec<i32>,
vis: &mut Vec<bool>,
ans: &mut Vec<Vec<i32>>,
i: usize,
) {
if i == nums.len() {
ans.push(t.clone());
return;
}
for j in 0..nums.len() {
if vis[j] || (j > 0 && nums[j] == nums[j - 1] && !vis[j - 1]) {
continue;
}
t[i] = nums[j];
vis[j] = true;
dfs(nums, t, vis, ans, i + 1);
vis[j] = false;
}
set.insert(nums[j]);
nums.swap(i, j);
Self::dfs(i + 1, nums, res);
nums.swap(i, j);
}
}

pub fn permute_unique(mut nums: Vec<i32>) -> Vec<Vec<i32>> {
let mut res = vec![];
Self::dfs(0, &mut nums, &mut res);
res
dfs(&nums, &mut t, &mut vis, &mut ans, 0);
ans
}
}
```

#### JavaScript

```js
/**
* @param {number[]} nums
* @return {number[][]}
*/
var permuteUnique = function (nums) {
nums.sort((a, b) => a - b);
const n = nums.length;
const ans = [];
const t = Array(n);
const vis = Array(n).fill(false);
const dfs = i => {
if (i === n) {
ans.push(t.slice());
return;
}
for (let j = 0; j < n; ++j) {
if (vis[j] || (j > 0 && nums[j] === nums[j - 1] && !vis[j - 1])) {
continue;
}
t[i] = nums[j];
vis[j] = true;
dfs(i + 1);
vis[j] = false;
}
};
dfs(0);
return ans;
};
```

#### C#

```cs
Expand Down
101 changes: 71 additions & 30 deletions solution/0000-0099/0047.Permutations II/README_EN.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,16 +54,16 @@ tags:

### Solution 1: Sorting + Backtracking

We can first sort the array, which allows us to place duplicate numbers together, making it easier for us to remove duplicates.
We can first sort the array so that duplicate numbers are placed together, making it easier to remove duplicates.

Next, we design a function $dfs(i)$, indicating that we need to fill in the number at the $i$th position. The specific implementation of the function is as follows:
Then, we design a function $\textit{dfs}(i)$, which represents the current number to be placed at the $i$-th position. The specific implementation of the function is as follows:

- If $i = n$, it means we have finished filling in, add the current permutation to the answer array, and then return.
- Otherwise, we enumerate the number $nums[j]$ at the $i$th position, where the range of $j$ is $[0, n - 1]$. We need to ensure that $nums[j]$ has not been used and is different from the number enumerated before, so as to ensure that the current permutation is not repeated. If the conditions are met, we can fill in $nums[j]$, and continue to recursively fill in the next position, that is, call $dfs(i + 1)$. After the recursive call ends, we need to mark $nums[j]$ as unused for later enumeration.
- If $i = n$, it means we have filled all positions, add the current permutation to the answer array, and then return.
- Otherwise, we enumerate the number $nums[j]$ for the $i$-th position, where the range of $j$ is $[0, n - 1]$. We need to ensure that $nums[j]$ has not been used and is different from the previously enumerated number to ensure that the current permutation is not duplicated. If the conditions are met, we can place $nums[j]$ and continue to recursively fill the next position by calling $\textit{dfs}(i + 1)$. After the recursive call ends, we need to mark $nums[j]$ as unused to facilitate subsequent enumeration.

In the main function, we first sort the array, then call $dfs(0)$, that is, start filling from the 0th position, and finally return the answer array.
In the main function, we first sort the array, then call $\textit{dfs}(0)$ to start filling from the 0th position, and finally return the answer array.

The time complexity is $O(n \times n!)$, and the space complexity is $O(n)$. Here, $n$ is the length of the array. We need to enumerate $n!$ times, and each enumeration takes $O(n)$ time to judge whether it is repeated. In addition, we need a marker array to mark whether each position has been used, so the space complexity is $O(n)$.
The time complexity is $O(n \times n!)$, and the space complexity is $O(n)$. Here, $n$ is the length of the array. We need to perform $n!$ enumerations, and each enumeration requires $O(n)$ time to check for duplicates. Additionally, we need a marker array to mark whether each position has been used, so the space complexity is $O(n)$.

Similar problems:

Expand Down Expand Up @@ -139,12 +139,12 @@ class Solution {
class Solution {
public:
vector<vector<int>> permuteUnique(vector<int>& nums) {
sort(nums.begin(), nums.end());
ranges::sort(nums);
int n = nums.size();
vector<vector<int>> ans;
vector<int> t(n);
vector<bool> vis(n);
function<void(int)> dfs = [&](int i) {
auto dfs = [&](this auto&& dfs, int i) {
if (i == n) {
ans.emplace_back(t);
return;
Expand All @@ -169,7 +169,7 @@ public:
```go
func permuteUnique(nums []int) (ans [][]int) {
sort.Ints(nums)
slices.Sort(nums)
n := len(nums)
t := make([]int, n)
vis := make([]bool, n)
Expand Down Expand Up @@ -201,8 +201,8 @@ function permuteUnique(nums: number[]): number[][] {
nums.sort((a, b) => a - b);
const n = nums.length;
const ans: number[][] = [];
const t: number[] = new Array(n);
const vis: boolean[] = new Array(n);
const t: number[] = Array(n);
const vis: boolean[] = Array(n).fill(false);
const dfs = (i: number) => {
if (i === n) {
ans.push(t.slice());
Expand All @@ -226,34 +226,75 @@ function permuteUnique(nums: number[]): number[][] {
#### Rust

```rust
use std::collections::HashSet;
impl Solution {
fn dfs(i: usize, nums: &mut Vec<i32>, res: &mut Vec<Vec<i32>>) {
pub fn permute_unique(mut nums: Vec<i32>) -> Vec<Vec<i32>> {
nums.sort();
let n = nums.len();
if i == n {
res.push(nums.clone());
return;
}
let mut set = HashSet::new();
for j in i..n {
if set.contains(&nums[j]) {
continue;
let mut ans = Vec::new();
let mut t = vec![0; n];
let mut vis = vec![false; n];

fn dfs(
nums: &Vec<i32>,
t: &mut Vec<i32>,
vis: &mut Vec<bool>,
ans: &mut Vec<Vec<i32>>,
i: usize,
) {
if i == nums.len() {
ans.push(t.clone());
return;
}
for j in 0..nums.len() {
if vis[j] || (j > 0 && nums[j] == nums[j - 1] && !vis[j - 1]) {
continue;
}
t[i] = nums[j];
vis[j] = true;
dfs(nums, t, vis, ans, i + 1);
vis[j] = false;
}
set.insert(nums[j]);
nums.swap(i, j);
Self::dfs(i + 1, nums, res);
nums.swap(i, j);
}
}

pub fn permute_unique(mut nums: Vec<i32>) -> Vec<Vec<i32>> {
let mut res = vec![];
Self::dfs(0, &mut nums, &mut res);
res
dfs(&nums, &mut t, &mut vis, &mut ans, 0);
ans
}
}
```

#### JavaScript

```js
/**
* @param {number[]} nums
* @return {number[][]}
*/
var permuteUnique = function (nums) {
nums.sort((a, b) => a - b);
const n = nums.length;
const ans = [];
const t = Array(n);
const vis = Array(n).fill(false);
const dfs = i => {
if (i === n) {
ans.push(t.slice());
return;
}
for (let j = 0; j < n; ++j) {
if (vis[j] || (j > 0 && nums[j] === nums[j - 1] && !vis[j - 1])) {
continue;
}
t[i] = nums[j];
vis[j] = true;
dfs(i + 1);
vis[j] = false;
}
};
dfs(0);
return ans;
};
```

#### C#

```cs
Expand Down
6 changes: 3 additions & 3 deletions solution/0000-0099/0047.Permutations II/Solution.cpp
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
class Solution {
public:
vector<vector<int>> permuteUnique(vector<int>& nums) {
sort(nums.begin(), nums.end());
ranges::sort(nums);
int n = nums.size();
vector<vector<int>> ans;
vector<int> t(n);
vector<bool> vis(n);
function<void(int)> dfs = [&](int i) {
auto dfs = [&](this auto&& dfs, int i) {
if (i == n) {
ans.emplace_back(t);
return;
Expand All @@ -24,4 +24,4 @@ class Solution {
dfs(0);
return ans;
}
};
};
2 changes: 1 addition & 1 deletion solution/0000-0099/0047.Permutations II/Solution.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
func permuteUnique(nums []int) (ans [][]int) {
sort.Ints(nums)
slices.Sort(nums)
n := len(nums)
t := make([]int, n)
vis := make([]bool, n)
Expand Down
28 changes: 28 additions & 0 deletions solution/0000-0099/0047.Permutations II/Solution.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/**
* @param {number[]} nums
* @return {number[][]}
*/
var permuteUnique = function (nums) {
nums.sort((a, b) => a - b);
const n = nums.length;
const ans = [];
const t = Array(n);
const vis = Array(n).fill(false);
const dfs = i => {
if (i === n) {
ans.push(t.slice());
return;
}
for (let j = 0; j < n; ++j) {
if (vis[j] || (j > 0 && nums[j] === nums[j - 1] && !vis[j - 1])) {
continue;
}
t[i] = nums[j];
vis[j] = true;
dfs(i + 1);
vis[j] = false;
}
};
dfs(0);
return ans;
};
Loading

0 comments on commit 59cb267

Please sign in to comment.