|
69 | 69 |
|
70 | 70 | <!-- 这里可写通用的实现逻辑 -->
|
71 | 71 |
|
| 72 | +**方法一:求下一个排列 + 逆序对** |
| 73 | + |
| 74 | +我们可以调用 $k$ 次 `next_permutation` 函数,得到第 $k$ 个最小妙数 $s$。 |
| 75 | + |
| 76 | +接下来,我们只需要计算 $num$ 需要经过多少次交换才能变成 $s$ 即可。 |
| 77 | + |
| 78 | +我们先考虑一个简单的情况,即 $num$ 中的数字都不相同。在这种情况下,我们可以直接把 $num$ 中的数字字符映射为下标。例如 $num$ 等于 `"54893"`,而 $s$ 等于 `"98345"`。我们将 $num$ 中的每个数字映射为下标,即: |
| 79 | + |
| 80 | +$$ |
| 81 | +\begin{aligned} |
| 82 | +num[0] &= 5 &\rightarrow& \quad 0 \\ |
| 83 | +num[1] &= 4 &\rightarrow& \quad 1 \\ |
| 84 | +num[2] &= 8 &\rightarrow& \quad 2 \\ |
| 85 | +num[3] &= 9 &\rightarrow& \quad 3 \\ |
| 86 | +num[4] &= 3 &\rightarrow& \quad 4 \\ |
| 87 | +\end{aligned} |
| 88 | +$$ |
| 89 | + |
| 90 | +那么 $s$ 中的每个数字映射为下标,就是 `"32410"`。这样,将 $num$ 变成 $s$ 所需要的交换次数,就等于 $s$ 映射后的下标数组的逆序对数。 |
| 91 | + |
| 92 | +如果 $num$ 中存在相同的数字,那么我们可以使用一个数组 $d$ 来记录每个数字出现的下标,其中 $d[i]$ 表示数字 $i$ 出现的下标列表。为了使得交换次数尽可能少,在将 $s$ 映射为下标数组时,我们只需要按顺序贪心地选择 $d$ 中对应数字的下标即可。 |
| 93 | + |
| 94 | +最后,我们可以直接使用双重循环来计算逆序对数,也可以使用树状数组来优化。 |
| 95 | + |
| 96 | +时间复杂度 $O(n \times (k + n))$,空间复杂度 $O(n)$。其中 $n$ 是 $num$ 的长度。 |
| 97 | + |
72 | 98 | <!-- tabs:start -->
|
73 | 99 |
|
74 | 100 | ### **Python3**
|
75 | 101 |
|
76 | 102 | <!-- 这里可写当前语言的特殊实现逻辑 -->
|
77 | 103 |
|
78 | 104 | ```python
|
79 |
| - |
| 105 | +class Solution: |
| 106 | + def getMinSwaps(self, num: str, k: int) -> int: |
| 107 | + def next_permutation(nums: List[str]) -> bool: |
| 108 | + n = len(nums) |
| 109 | + i = n - 2 |
| 110 | + while i >= 0 and nums[i] >= nums[i + 1]: |
| 111 | + i -= 1 |
| 112 | + if i < 0: |
| 113 | + return False |
| 114 | + j = n - 1 |
| 115 | + while j >= 0 and nums[j] <= nums[i]: |
| 116 | + j -= 1 |
| 117 | + nums[i], nums[j] = nums[j], nums[i] |
| 118 | + nums[i + 1 : n] = nums[i + 1 : n][::-1] |
| 119 | + return True |
| 120 | + |
| 121 | + s = list(num) |
| 122 | + for _ in range(k): |
| 123 | + next_permutation(s) |
| 124 | + d = [[] for _ in range(10)] |
| 125 | + idx = [0] * 10 |
| 126 | + n = len(s) |
| 127 | + for i, c in enumerate(num): |
| 128 | + j = ord(c) - ord("0") |
| 129 | + d[j].append(i) |
| 130 | + arr = [0] * n |
| 131 | + for i, c in enumerate(s): |
| 132 | + j = ord(c) - ord("0") |
| 133 | + arr[i] = d[j][idx[j]] |
| 134 | + idx[j] += 1 |
| 135 | + return sum(arr[j] > arr[i] for i in range(n) for j in range(i)) |
80 | 136 | ```
|
81 | 137 |
|
82 | 138 | ### **Java**
|
83 | 139 |
|
84 | 140 | <!-- 这里可写当前语言的特殊实现逻辑 -->
|
85 | 141 |
|
86 | 142 | ```java
|
| 143 | +class Solution { |
| 144 | + public int getMinSwaps(String num, int k) { |
| 145 | + char[] s = num.toCharArray(); |
| 146 | + for (int i = 0; i < k; ++i) { |
| 147 | + nextPermutation(s); |
| 148 | + } |
| 149 | + List<Integer>[] d = new List[10]; |
| 150 | + Arrays.setAll(d, i -> new ArrayList<>()); |
| 151 | + int n = s.length; |
| 152 | + for (int i = 0; i < n; ++i) { |
| 153 | + d[num.charAt(i) - '0'].add(i); |
| 154 | + } |
| 155 | + int[] idx = new int[10]; |
| 156 | + int[] arr = new int[n]; |
| 157 | + for (int i = 0; i < n; ++i) { |
| 158 | + arr[i] = d[s[i] - '0'].get(idx[s[i] - '0']++); |
| 159 | + } |
| 160 | + int ans = 0; |
| 161 | + for (int i = 0; i < n; ++i) { |
| 162 | + for (int j = 0; j < i; ++j) { |
| 163 | + if (arr[j] > arr[i]) { |
| 164 | + ++ans; |
| 165 | + } |
| 166 | + } |
| 167 | + } |
| 168 | + return ans; |
| 169 | + } |
| 170 | + |
| 171 | + private boolean nextPermutation(char[] nums) { |
| 172 | + int n = nums.length; |
| 173 | + int i = n - 2; |
| 174 | + while (i >= 0 && nums[i] >= nums[i + 1]) { |
| 175 | + --i; |
| 176 | + } |
| 177 | + if (i < 0) { |
| 178 | + return false; |
| 179 | + } |
| 180 | + int j = n - 1; |
| 181 | + while (j >= 0 && nums[i] >= nums[j]) { |
| 182 | + --j; |
| 183 | + } |
| 184 | + swap(nums, i++, j); |
| 185 | + for (j = n - 1; i < j; ++i, --j) { |
| 186 | + swap(nums, i, j); |
| 187 | + } |
| 188 | + return true; |
| 189 | + } |
| 190 | + |
| 191 | + private void swap(char[] nums, int i, int j) { |
| 192 | + char t = nums[i]; |
| 193 | + nums[i] = nums[j]; |
| 194 | + nums[j] = t; |
| 195 | + } |
| 196 | +} |
| 197 | +``` |
| 198 | + |
| 199 | +### **C++** |
| 200 | + |
| 201 | +```cpp |
| 202 | +class Solution { |
| 203 | +public: |
| 204 | + int getMinSwaps(string num, int k) { |
| 205 | + string s = num; |
| 206 | + for (int i = 0; i < k; ++i) { |
| 207 | + next_permutation(begin(s), end(num)); |
| 208 | + } |
| 209 | + vector<int> d[10]; |
| 210 | + int n = num.size(); |
| 211 | + for (int i = 0; i < n; ++i) { |
| 212 | + d[num[i] - '0'].push_back(i); |
| 213 | + } |
| 214 | + int idx[10]{}; |
| 215 | + vector<int> arr(n); |
| 216 | + for (int i = 0; i < n; ++i) { |
| 217 | + arr[i] = d[s[i] - '0'][idx[s[i] - '0']++]; |
| 218 | + } |
| 219 | + int ans = 0; |
| 220 | + for (int i = 0; i < n; ++i) { |
| 221 | + for (int j = 0; j < i; ++j) { |
| 222 | + if (arr[j] > arr[i]) { |
| 223 | + ++ans; |
| 224 | + } |
| 225 | + } |
| 226 | + } |
| 227 | + return ans; |
| 228 | + } |
| 229 | +}; |
| 230 | +``` |
| 231 | +
|
| 232 | +### **Go** |
| 233 | +
|
| 234 | +```go |
| 235 | +func getMinSwaps(num string, k int) (ans int) { |
| 236 | + s := []byte(num) |
| 237 | + for ; k > 0; k-- { |
| 238 | + nextPermutation(s) |
| 239 | + } |
| 240 | + d := [10][]int{} |
| 241 | + for i, c := range num { |
| 242 | + j := int(c - '0') |
| 243 | + d[j] = append(d[j], i) |
| 244 | + } |
| 245 | + idx := [10]int{} |
| 246 | + n := len(s) |
| 247 | + arr := make([]int, n) |
| 248 | + for i, c := range s { |
| 249 | + j := int(c - '0') |
| 250 | + arr[i] = d[j][idx[j]] |
| 251 | + idx[j]++ |
| 252 | + } |
| 253 | + for i := 0; i < n; i++ { |
| 254 | + for j := 0; j < i; j++ { |
| 255 | + if arr[j] > arr[i] { |
| 256 | + ans++ |
| 257 | + } |
| 258 | + } |
| 259 | + } |
| 260 | + return |
| 261 | +} |
| 262 | +
|
| 263 | +func nextPermutation(nums []byte) bool { |
| 264 | + n := len(nums) |
| 265 | + i := n - 2 |
| 266 | + for i >= 0 && nums[i] >= nums[i+1] { |
| 267 | + i-- |
| 268 | + } |
| 269 | + if i < 0 { |
| 270 | + return false |
| 271 | + } |
| 272 | + j := n - 1 |
| 273 | + for j >= 0 && nums[j] <= nums[i] { |
| 274 | + j-- |
| 275 | + } |
| 276 | + nums[i], nums[j] = nums[j], nums[i] |
| 277 | + for i, j = i+1, n-1; i < j; i, j = i+1, j-1 { |
| 278 | + nums[i], nums[j] = nums[j], nums[i] |
| 279 | + } |
| 280 | + return true |
| 281 | +} |
| 282 | +``` |
87 | 283 |
|
| 284 | +### **TypeScript** |
| 285 | + |
| 286 | +```ts |
| 287 | +function getMinSwaps(num: string, k: number): number { |
| 288 | + const n = num.length; |
| 289 | + const s = num.split(''); |
| 290 | + for (let i = 0; i < k; ++i) { |
| 291 | + nextPermutation(s); |
| 292 | + } |
| 293 | + const d: number[][] = Array.from({ length: 10 }, () => []); |
| 294 | + for (let i = 0; i < n; ++i) { |
| 295 | + d[+num[i]].push(i); |
| 296 | + } |
| 297 | + const idx: number[] = Array(10).fill(0); |
| 298 | + const arr: number[] = []; |
| 299 | + for (let i = 0; i < n; ++i) { |
| 300 | + arr.push(d[+s[i]][idx[+s[i]]++]); |
| 301 | + } |
| 302 | + let ans = 0; |
| 303 | + for (let i = 0; i < n; ++i) { |
| 304 | + for (let j = 0; j < i; ++j) { |
| 305 | + if (arr[j] > arr[i]) { |
| 306 | + ans++; |
| 307 | + } |
| 308 | + } |
| 309 | + } |
| 310 | + return ans; |
| 311 | +} |
| 312 | + |
| 313 | +function nextPermutation(nums: string[]): boolean { |
| 314 | + const n = nums.length; |
| 315 | + let i = n - 2; |
| 316 | + while (i >= 0 && nums[i] >= nums[i + 1]) { |
| 317 | + i--; |
| 318 | + } |
| 319 | + if (i < 0) { |
| 320 | + return false; |
| 321 | + } |
| 322 | + let j = n - 1; |
| 323 | + while (j >= 0 && nums[i] >= nums[j]) { |
| 324 | + j--; |
| 325 | + } |
| 326 | + [nums[i], nums[j]] = [nums[j], nums[i]]; |
| 327 | + for (i = i + 1, j = n - 1; i < j; ++i, --j) { |
| 328 | + [nums[i], nums[j]] = [nums[j], nums[i]]; |
| 329 | + } |
| 330 | + return true; |
| 331 | +} |
88 | 332 | ```
|
89 | 333 |
|
90 | 334 | ### **...**
|
|
0 commit comments