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: add solutions to lc problem: No.1850 #2137

Merged
merged 2 commits into from
Dec 21, 2023
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
Original file line number Diff line number Diff line change
Expand Up @@ -69,22 +69,266 @@

<!-- 这里可写通用的实现逻辑 -->

**方法一:求下一个排列 + 逆序对**

我们可以调用 $k$ 次 `next_permutation` 函数,得到第 $k$ 个最小妙数 $s$。

接下来,我们只需要计算 $num$ 需要经过多少次交换才能变成 $s$ 即可。

我们先考虑一个简单的情况,即 $num$ 中的数字都不相同。在这种情况下,我们可以直接把 $num$ 中的数字字符映射为下标。例如 $num$ 等于 `"54893"`,而 $s$ 等于 `"98345"`。我们将 $num$ 中的每个数字映射为下标,即:

$$
\begin{aligned}
num[0] &= 5 &\rightarrow& \quad 0 \\
num[1] &= 4 &\rightarrow& \quad 1 \\
num[2] &= 8 &\rightarrow& \quad 2 \\
num[3] &= 9 &\rightarrow& \quad 3 \\
num[4] &= 3 &\rightarrow& \quad 4 \\
\end{aligned}
$$

那么 $s$ 中的每个数字映射为下标,就是 `"32410"`。这样,将 $num$ 变成 $s$ 所需要的交换次数,就等于 $s$ 映射后的下标数组的逆序对数。

如果 $num$ 中存在相同的数字,那么我们可以使用一个数组 $d$ 来记录每个数字出现的下标,其中 $d[i]$ 表示数字 $i$ 出现的下标列表。为了使得交换次数尽可能少,在将 $s$ 映射为下标数组时,我们只需要按顺序贪心地选择 $d$ 中对应数字的下标即可。

最后,我们可以直接使用双重循环来计算逆序对数,也可以使用树状数组来优化。

时间复杂度 $O(n \times (k + n))$,空间复杂度 $O(n)$。其中 $n$ 是 $num$ 的长度。

<!-- tabs:start -->

### **Python3**

<!-- 这里可写当前语言的特殊实现逻辑 -->

```python

class Solution:
def getMinSwaps(self, num: str, k: int) -> int:
def next_permutation(nums: List[str]) -> bool:
n = len(nums)
i = n - 2
while i >= 0 and nums[i] >= nums[i + 1]:
i -= 1
if i < 0:
return False
j = n - 1
while j >= 0 and nums[j] <= nums[i]:
j -= 1
nums[i], nums[j] = nums[j], nums[i]
nums[i + 1 : n] = nums[i + 1 : n][::-1]
return True

s = list(num)
for _ in range(k):
next_permutation(s)
d = [[] for _ in range(10)]
idx = [0] * 10
n = len(s)
for i, c in enumerate(num):
j = ord(c) - ord("0")
d[j].append(i)
arr = [0] * n
for i, c in enumerate(s):
j = ord(c) - ord("0")
arr[i] = d[j][idx[j]]
idx[j] += 1
return sum(arr[j] > arr[i] for i in range(n) for j in range(i))
```

### **Java**

<!-- 这里可写当前语言的特殊实现逻辑 -->

```java
class Solution {
public int getMinSwaps(String num, int k) {
char[] s = num.toCharArray();
for (int i = 0; i < k; ++i) {
nextPermutation(s);
}
List<Integer>[] d = new List[10];
Arrays.setAll(d, i -> new ArrayList<>());
int n = s.length;
for (int i = 0; i < n; ++i) {
d[num.charAt(i) - '0'].add(i);
}
int[] idx = new int[10];
int[] arr = new int[n];
for (int i = 0; i < n; ++i) {
arr[i] = d[s[i] - '0'].get(idx[s[i] - '0']++);
}
int ans = 0;
for (int i = 0; i < n; ++i) {
for (int j = 0; j < i; ++j) {
if (arr[j] > arr[i]) {
++ans;
}
}
}
return ans;
}

private boolean nextPermutation(char[] nums) {
int n = nums.length;
int i = n - 2;
while (i >= 0 && nums[i] >= nums[i + 1]) {
--i;
}
if (i < 0) {
return false;
}
int j = n - 1;
while (j >= 0 && nums[i] >= nums[j]) {
--j;
}
swap(nums, i++, j);
for (j = n - 1; i < j; ++i, --j) {
swap(nums, i, j);
}
return true;
}

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

### **C++**

```cpp
class Solution {
public:
int getMinSwaps(string num, int k) {
string s = num;
for (int i = 0; i < k; ++i) {
next_permutation(begin(s), end(num));
}
vector<int> d[10];
int n = num.size();
for (int i = 0; i < n; ++i) {
d[num[i] - '0'].push_back(i);
}
int idx[10]{};
vector<int> arr(n);
for (int i = 0; i < n; ++i) {
arr[i] = d[s[i] - '0'][idx[s[i] - '0']++];
}
int ans = 0;
for (int i = 0; i < n; ++i) {
for (int j = 0; j < i; ++j) {
if (arr[j] > arr[i]) {
++ans;
}
}
}
return ans;
}
};
```

### **Go**

```go
func getMinSwaps(num string, k int) (ans int) {
s := []byte(num)
for ; k > 0; k-- {
nextPermutation(s)
}
d := [10][]int{}
for i, c := range num {
j := int(c - '0')
d[j] = append(d[j], i)
}
idx := [10]int{}
n := len(s)
arr := make([]int, n)
for i, c := range s {
j := int(c - '0')
arr[i] = d[j][idx[j]]
idx[j]++
}
for i := 0; i < n; i++ {
for j := 0; j < i; j++ {
if arr[j] > arr[i] {
ans++
}
}
}
return
}

func nextPermutation(nums []byte) bool {
n := len(nums)
i := n - 2
for i >= 0 && nums[i] >= nums[i+1] {
i--
}
if i < 0 {
return false
}
j := n - 1
for j >= 0 && nums[j] <= nums[i] {
j--
}
nums[i], nums[j] = nums[j], nums[i]
for i, j = i+1, n-1; i < j; i, j = i+1, j-1 {
nums[i], nums[j] = nums[j], nums[i]
}
return true
}
```

### **TypeScript**

```ts
function getMinSwaps(num: string, k: number): number {
const n = num.length;
const s = num.split('');
for (let i = 0; i < k; ++i) {
nextPermutation(s);
}
const d: number[][] = Array.from({ length: 10 }, () => []);
for (let i = 0; i < n; ++i) {
d[+num[i]].push(i);
}
const idx: number[] = Array(10).fill(0);
const arr: number[] = [];
for (let i = 0; i < n; ++i) {
arr.push(d[+s[i]][idx[+s[i]]++]);
}
let ans = 0;
for (let i = 0; i < n; ++i) {
for (let j = 0; j < i; ++j) {
if (arr[j] > arr[i]) {
ans++;
}
}
}
return ans;
}

function nextPermutation(nums: string[]): boolean {
const n = nums.length;
let i = n - 2;
while (i >= 0 && nums[i] >= nums[i + 1]) {
i--;
}
if (i < 0) {
return false;
}
let j = n - 1;
while (j >= 0 && nums[i] >= nums[j]) {
j--;
}
[nums[i], nums[j]] = [nums[j], nums[i]];
for (i = i + 1, j = n - 1; i < j; ++i, --j) {
[nums[i], nums[j]] = [nums[j], nums[i]];
}
return true;
}
```

### **...**
Expand Down
Loading