Skip to content

Commit 2e542d1

Browse files
authored
feat: add solutions to lc problem: No.3149 (doocs#2809)
No.3149.Find the Minimum Cost Array Permutation
1 parent 6c115d0 commit 2e542d1

File tree

7 files changed

+651
-8
lines changed

7 files changed

+651
-8
lines changed

solution/3100-3199/3149.Find the Minimum Cost Array Permutation/README.md

+223-4
Original file line numberDiff line numberDiff line change
@@ -55,24 +55,243 @@
5555

5656
## 解法
5757

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}$ 的长度。
5974

6075
<!-- tabs:start -->
6176

6277
```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
64105
```
65106

66107
```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+
}
68155
```
69156

70157
```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+
};
72200
```
73201
74202
```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+
```
75256

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+
}
76295
```
77296

78297
<!-- tabs:end -->

0 commit comments

Comments
 (0)