|
55 | 55 |
|
56 | 56 | ## 解法
|
57 | 57 |
|
58 |
| -### 方法一 |
| 58 | +### 方法一:记忆化搜索 |
| 59 | + |
| 60 | +我们注意到,对于任意一个排列 $\text{perm}$,把它循环向左移动任意次,得到的排列分数依然是相同的。由于题目要求返回字典序最小的排列,因此我们可以确定排列的第一个元素一定是 $0$。 |
| 61 | + |
| 62 | +另外,由于题目的数据范围不超过 $14$,我们可以考虑使用状态压缩的方法,来表示当前排列选取的数字集合。我们用一个长度为 $n$ 的二进制数 $\text{mask}$ 来表示当前排列选取的数字集合,其中 $\text{mask}$ 的第 $i$ 位为 $1$ 表示数字 $i$ 已经被选取,为 $0$ 表示数字 $i$ 还未被选取。 |
| 63 | + |
| 64 | +我们设计一个函数 $\text{dfs}(\text{mask}, \text{pre})$,表示当前排列选取的数字集合为 $\text{mask}$,且最后一个选取的数字为 $\text{pre}$ 时,得到的排列的最小分数。初始时我们将数字 $0$ 加入到排列中。 |
| 65 | + |
| 66 | +函数 $\text{dfs}(\text{mask}, \text{pre})$ 的计算过程如下: |
| 67 | + |
| 68 | +- 如果 $\text{mask}$ 的二进制表示中 $1$ 的个数为 $n$,即 $\text{mask} = 2^n - 1$,表示所有数字都已经被选取,此时返回 $\text{abs}(\text{pre} - \text{nums}[0])$; |
| 69 | +- 否则,我们枚举下一个选取的数字 $\text{cur}$,如果数字 $\text{cur}$ 还未被选取,那么我们可以将数字 $\text{cur}$ 加入到排列中,此时排列的分数为 $|\text{pre} - \text{nums}[\text{cur}]| + \text{dfs}(\text{mask} \, | \, 1 << \text{cur}, \text{cur})$,我们需要取所有 $\text{cur}$ 中分数的最小值。 |
| 70 | + |
| 71 | +最后,我们利用一个函数 $\text{g}(\text{mask}, \text{pre})$ 来构造得到最小分数的排列。我们首先将数字 $\text{pre}$ 加入到排列中,然后枚举下一个选取的数字 $\text{cur}$,如果数字 $\text{cur}$ 还未被选取,且满足 $|\text{pre} - \text{nums}[\text{cur}]| + \text{dfs}(\text{mask} \, | \, 1 << \text{cur}, \text{cur})$ 的值等于 $\text{dfs}(\text{mask}, \text{pre})$,那么我们就可以将数字 $\text{cur}$ 加入到排列中。 |
| 72 | + |
| 73 | +时间复杂度 $(n^2 \times 2^n)$,空间复杂度 $O(n \times 2^n)$。其中 $n$ 为数组 $\text{nums}$ 的长度。 |
59 | 74 |
|
60 | 75 | <!-- tabs:start -->
|
61 | 76 |
|
62 | 77 | ```python
|
63 |
| - |
| 78 | +class Solution: |
| 79 | + def findPermutation(self, nums: List[int]) -> List[int]: |
| 80 | + @cache |
| 81 | + def dfs(mask: int, pre: int) -> int: |
| 82 | + if mask == (1 << n) - 1: |
| 83 | + return abs(pre - nums[0]) |
| 84 | + res = inf |
| 85 | + for cur in range(1, n): |
| 86 | + if mask >> cur & 1 ^ 1: |
| 87 | + res = min(res, abs(pre - nums[cur]) + dfs(mask | 1 << cur, cur)) |
| 88 | + return res |
| 89 | + |
| 90 | + def g(mask: int, pre: int): |
| 91 | + ans.append(pre) |
| 92 | + if mask == (1 << n) - 1: |
| 93 | + return |
| 94 | + res = dfs(mask, pre) |
| 95 | + for cur in range(1, n): |
| 96 | + if mask >> cur & 1 ^ 1: |
| 97 | + if abs(pre - nums[cur]) + dfs(mask | 1 << cur, cur) == res: |
| 98 | + g(mask | 1 << cur, cur) |
| 99 | + break |
| 100 | + |
| 101 | + n = len(nums) |
| 102 | + ans = [] |
| 103 | + g(1, 0) |
| 104 | + return ans |
64 | 105 | ```
|
65 | 106 |
|
66 | 107 | ```java
|
67 |
| - |
| 108 | +class Solution { |
| 109 | + private Integer[][] f; |
| 110 | + private int[] nums; |
| 111 | + private int[] ans; |
| 112 | + private int n; |
| 113 | + |
| 114 | + public int[] findPermutation(int[] nums) { |
| 115 | + n = nums.length; |
| 116 | + ans = new int[n]; |
| 117 | + this.nums = nums; |
| 118 | + f = new Integer[1 << n][n]; |
| 119 | + g(1, 0, 0); |
| 120 | + return ans; |
| 121 | + } |
| 122 | + |
| 123 | + private int dfs(int mask, int pre) { |
| 124 | + if (mask == (1 << n) - 1) { |
| 125 | + return Math.abs(pre - nums[0]); |
| 126 | + } |
| 127 | + if (f[mask][pre] != null) { |
| 128 | + return f[mask][pre]; |
| 129 | + } |
| 130 | + int res = Integer.MAX_VALUE; |
| 131 | + for (int cur = 1; cur < n; ++cur) { |
| 132 | + if ((mask >> cur & 1) == 0) { |
| 133 | + res = Math.min(res, Math.abs(pre - nums[cur]) + dfs(mask | 1 << cur, cur)); |
| 134 | + } |
| 135 | + } |
| 136 | + return f[mask][pre] = res; |
| 137 | + } |
| 138 | + |
| 139 | + private void g(int mask, int pre, int k) { |
| 140 | + ans[k] = pre; |
| 141 | + if (mask == (1 << n) - 1) { |
| 142 | + return; |
| 143 | + } |
| 144 | + int res = dfs(mask, pre); |
| 145 | + for (int cur = 1; cur < n; ++cur) { |
| 146 | + if ((mask >> cur & 1) == 0) { |
| 147 | + if (Math.abs(pre - nums[cur]) + dfs(mask | 1 << cur, cur) == res) { |
| 148 | + g(mask | 1 << cur, cur, k + 1); |
| 149 | + break; |
| 150 | + } |
| 151 | + } |
| 152 | + } |
| 153 | + } |
| 154 | +} |
68 | 155 | ```
|
69 | 156 |
|
70 | 157 | ```cpp
|
71 |
| - |
| 158 | +class Solution { |
| 159 | +public: |
| 160 | + vector<int> findPermutation(vector<int>& nums) { |
| 161 | + int n = nums.size(); |
| 162 | + vector<int> ans; |
| 163 | + int f[1 << n][n]; |
| 164 | + memset(f, -1, sizeof(f)); |
| 165 | + function<int(int, int)> dfs = [&](int mask, int pre) { |
| 166 | + if (mask == (1 << n) - 1) { |
| 167 | + return abs(pre - nums[0]); |
| 168 | + } |
| 169 | + int* res = &f[mask][pre]; |
| 170 | + if (*res != -1) { |
| 171 | + return *res; |
| 172 | + } |
| 173 | + *res = INT_MAX; |
| 174 | + for (int cur = 1; cur < n; ++cur) { |
| 175 | + if (mask >> cur & 1 ^ 1) { |
| 176 | + *res = min(*res, abs(pre - nums[cur]) + dfs(mask | 1 << cur, cur)); |
| 177 | + } |
| 178 | + } |
| 179 | + return *res; |
| 180 | + }; |
| 181 | + function<void(int, int)> g = [&](int mask, int pre) { |
| 182 | + ans.push_back(pre); |
| 183 | + if (mask == (1 << n) - 1) { |
| 184 | + return; |
| 185 | + } |
| 186 | + int res = dfs(mask, pre); |
| 187 | + for (int cur = 1; cur < n; ++cur) { |
| 188 | + if (mask >> cur & 1 ^ 1) { |
| 189 | + if (abs(pre - nums[cur]) + dfs(mask | 1 << cur, cur) == res) { |
| 190 | + g(mask | 1 << cur, cur); |
| 191 | + break; |
| 192 | + } |
| 193 | + } |
| 194 | + } |
| 195 | + }; |
| 196 | + g(1, 0); |
| 197 | + return ans; |
| 198 | + } |
| 199 | +}; |
72 | 200 | ```
|
73 | 201 |
|
74 | 202 | ```go
|
| 203 | +func findPermutation(nums []int) (ans []int) { |
| 204 | + n := len(nums) |
| 205 | + f := make([][]int, 1<<n) |
| 206 | + for i := range f { |
| 207 | + f[i] = make([]int, n) |
| 208 | + for j := range f[i] { |
| 209 | + f[i][j] = -1 |
| 210 | + } |
| 211 | + } |
| 212 | + var dfs func(int, int) int |
| 213 | + dfs = func(mask, pre int) int { |
| 214 | + if mask == 1<<n-1 { |
| 215 | + return abs(pre - nums[0]) |
| 216 | + } |
| 217 | + if f[mask][pre] != -1 { |
| 218 | + return f[mask][pre] |
| 219 | + } |
| 220 | + res := &f[mask][pre] |
| 221 | + *res = math.MaxInt32 |
| 222 | + for cur := 1; cur < n; cur++ { |
| 223 | + if mask>>cur&1 == 0 { |
| 224 | + *res = min(*res, abs(pre-nums[cur])+dfs(mask|1<<cur, cur)) |
| 225 | + } |
| 226 | + } |
| 227 | + return *res |
| 228 | + } |
| 229 | + var g func(int, int) |
| 230 | + g = func(mask, pre int) { |
| 231 | + ans = append(ans, pre) |
| 232 | + if mask == 1<<n-1 { |
| 233 | + return |
| 234 | + } |
| 235 | + res := dfs(mask, pre) |
| 236 | + for cur := 1; cur < n; cur++ { |
| 237 | + if mask>>cur&1 == 0 { |
| 238 | + if abs(pre-nums[cur])+dfs(mask|1<<cur, cur) == res { |
| 239 | + g(mask|1<<cur, cur) |
| 240 | + break |
| 241 | + } |
| 242 | + } |
| 243 | + } |
| 244 | + } |
| 245 | + g(1, 0) |
| 246 | + return |
| 247 | +} |
| 248 | +
|
| 249 | +func abs(x int) int { |
| 250 | + if x < 0 { |
| 251 | + return -x |
| 252 | + } |
| 253 | + return x |
| 254 | +} |
| 255 | +``` |
75 | 256 |
|
| 257 | +```ts |
| 258 | +function findPermutation(nums: number[]): number[] { |
| 259 | + const n = nums.length; |
| 260 | + const ans: number[] = []; |
| 261 | + const f: number[][] = Array.from({ length: 1 << n }, () => Array(n).fill(-1)); |
| 262 | + const dfs = (mask: number, pre: number): number => { |
| 263 | + if (mask === (1 << n) - 1) { |
| 264 | + return Math.abs(pre - nums[0]); |
| 265 | + } |
| 266 | + if (f[mask][pre] !== -1) { |
| 267 | + return f[mask][pre]; |
| 268 | + } |
| 269 | + let res = Infinity; |
| 270 | + for (let cur = 1; cur < n; ++cur) { |
| 271 | + if (((mask >> cur) & 1) ^ 1) { |
| 272 | + res = Math.min(res, Math.abs(pre - nums[cur]) + dfs(mask | (1 << cur), cur)); |
| 273 | + } |
| 274 | + } |
| 275 | + return (f[mask][pre] = res); |
| 276 | + }; |
| 277 | + const g = (mask: number, pre: number) => { |
| 278 | + ans.push(pre); |
| 279 | + if (mask === (1 << n) - 1) { |
| 280 | + return; |
| 281 | + } |
| 282 | + const res = dfs(mask, pre); |
| 283 | + for (let cur = 1; cur < n; ++cur) { |
| 284 | + if (((mask >> cur) & 1) ^ 1) { |
| 285 | + if (Math.abs(pre - nums[cur]) + dfs(mask | (1 << cur), cur) === res) { |
| 286 | + g(mask | (1 << cur), cur); |
| 287 | + break; |
| 288 | + } |
| 289 | + } |
| 290 | + } |
| 291 | + }; |
| 292 | + g(1, 0); |
| 293 | + return ans; |
| 294 | +} |
76 | 295 | ```
|
77 | 296 |
|
78 | 297 | <!-- tabs:end -->
|
|
0 commit comments