1718. 构建字典序最大的可行序列
1718. 构建字典序最大的可行序列
题目
Given an integer n, find a sequence that satisfies all of the following:
- The integer
1occurs once in the sequence. - Each integer between
2andnoccurs twice in the sequence. - For every integer
ibetween2andn, the distance between the two occurrences ofiis exactlyi.
The distance between two numbers on the sequence, a[i] and a[j], is the absolute difference of their indices, |j - i|.
Return thelexicographically largest sequence . It is guaranteed that under the given constraints, there is always a solution.
A sequence a is lexicographically larger than a sequence b (of the same length) if in the first position where a and b differ, sequence a has a number greater than the corresponding number in b. For example, [0,1,9,0] is lexicographically larger than [0,1,5,6] because the first position they differ is at the third number, and 9 is greater than 5.
Example 1:
Input: n = 3
Output: [3,1,2,3,2]
Explanation: [2,3,2,1,3] is also a valid sequence, but [3,1,2,3,2] is the lexicographically largest valid sequence.
Example 2:
Input: n = 5
Output: [5,3,1,4,3,5,2,4,2]
Constraints:
1 <= n <= 20
题目大意
给你一个整数 n ,请你找到满足下面条件的一个序列:
- 整数
1在序列中只出现一次。 2到n之间每个整数都恰好出现两次。- 对于每个
2到n之间的整数i,两个i之间出现的距离恰好为i。
序列里面两个数 a[i] 和 a[j] 之间的 距离 ,我们定义为它们下标绝对值之差 |j - i| 。
请你返回满足上述条件中 字典序最大 的序列。题目保证在给定限制条件下,一定存在解。
一个序列 a 被认为比序列 b (两者长度相同)字典序更大的条件是: a 和 b 中第一个不一样的数字处,a 序列的数字比 b 序列的数字大。比方说,[0,1,9,0] 比 [0,1,5,6] 字典序更大,因为第一个不同的位置是第三个数字,且 9 比 5 大。
示例 1:
输入: n = 3
输出:[3,1,2,3,2]
解释:[2,3,2,1,3] 也是一个可行的序列,但是 [3,1,2,3,2] 是字典序最大的序列。
示例 2:
输入: n = 5
输出:[5,3,1,4,3,5,2,4,2]
提示:
1 <= n <= 20
解题思路
由于 res 的位置需要满足一定的间隔关系,因此可以采用回溯(Backtracking)+ 剪枝的策略来构造数组。
- 回溯框架
使用递归方法 backtrack(idx),从索引 idx = 0 开始,尝试在 res 中填入 n 到 1,直到数组填满。
- 回溯细节
在 idx 位置尝试放置数字 num(从 n 递减到 1):
- 跳过已填充的位置:如果
res[idx]已有值,直接递归到下一个索引。 - 检查
num是否可以放置:num需要占据idx和idx + num两个位置。idx + num不能超出res数组范围。idx + num位置必须是空的。- 特殊情况:
num == 1只占据一个位置。
- 放置
num,然后递归继续:- 标记
used[num] = true,填充res[idx] = res[idx + num] = num。 - 递归调用
backtrack(idx + 1)。 - 如果找到解,返回
true。 - 回溯(撤销选择):如果递归失败,则撤销填充,并继续尝试更小的
num。
- 标记
- 剪枝优化
按
n → 1递减放置:优先尝试较大的num,保证字典序最大。跳过已填充的位置:
if (res[idx] !== 0) backtrack(idx + 1)避免重复计算。提前终止无效路径:
if (used[num]) continue:避免重复放置num。if (next >= len || res[next] !== 0) continue:避免超出范围或覆盖已填充位置。
复杂度分析
时间复杂度:
O(n * n!)- 由于
res长度为2n - 1,理论上我们可能尝试O(n!)种排列方式。 - 但由于剪枝优化,实际情况远低于
O(n!)。 - 近似时间复杂度可以认为是
O(n * n!)级别。
- 由于
空间复杂度:
O(n)。- 主要由
res(O(2n-1) ≈ O(n))和used(O(n))数组组成,共O(n)额外空间。 - 递归调用栈最深
O(n) - 因此总空间复杂度为
O(n)。
- 主要由
代码
/**
* @param {number} n
* @return {number[]}
*/
var constructDistancedSequence = function (n) {
const len = 2 * n - 1;
let res = new Array(len).fill(0);
let used = new Array(n + 1).fill(false);
const backtrack = (idx) => {
if (idx == len) {
return true;
}
if (res[idx] !== 0) {
return backtrack(idx + 1);
}
// 尝试在 res 中填入 n 到 1
for (let num = n; num > 0; num--) {
// 剪枝
if (used[num]) {
continue;
}
const next = num == 1 ? idx : num + idx;
if (next >= len || res[next] !== 0) {
continue;
}
// 放置 num
res[idx] = res[next] = num;
used[num] = true;
// 递归
if (backtrack(idx + 1)) {
return true;
}
// 回溯
res[idx] = res[next] = 0;
used[num] = false;
}
return false;
};
backtrack(0);
return res;
};
相关题目
| 题号 | 标题 | 题解 | 标签 | 难度 | 力扣 |
|---|---|---|---|---|---|
| 2597 | 美丽子集的数目 | 数组 哈希表 数学 4+ | 🟠 | 🀄️ 🔗 |
