Medium
题目描述
长度为 n 的数组 nums 是美丽的,如果:
- nums 是范围 [1, n] 内整数的一个排列。
- 对于每个 0 <= i < j < n,不存在下标 k 满足 i < k < j 且 2 * nums[k] == nums[i] + nums[j]。
给你整数 n,返回任意一个长度为 n 的美丽数组 nums。题目数据保证对于给定的 n 至少存在一个有效答案。
示例 1:
输入:n = 4
输出:[2,1,4,3]
示例 2:
输入:n = 5
输出:[3,1,2,5,4]
提示:
- 1 <= n <= 1000
解题思路
这道题的关键是理解美丽数组的性质并利用分治思想构造。
核心观察:
- 如果数组 A 是美丽的,那么对于任意常数 c 和 d,数组 [c*A[i] + d] 也是美丽的
- 奇数和偶数的和不可能是偶数,这启发我们将数组分为奇数部分和偶数部分
构造思路:
- 对于长度为 n 的美丽数组,我们可以将其分为两部分:
- 左半部分:所有奇数位置的元素
- 右半部分:所有偶数位置的元素
- 由于奇数 + 奇数 = 偶数,偶数 + 偶数 = 偶数,奇数 + 偶数 = 奇数
- 如果我们确保左半部分都是奇数,右半部分都是偶数,那么任意三元组 (i,k,j) 中,如果 i 来自左半部分,j 来自右半部分,则 nums[i] + nums[j] 是奇数,不可能等于 2*nums[k]
递归构造:
- 递归构造长度为 (n+1)/2 的美丽数组作为奇数部分
- 递归构造长度为 n/2 的美丽数组作为偶数部分
- 将奇数部分映射为 2x-1(变成奇数),偶数部分映射为 2x(变成偶数)
- 合并两部分得到最终结果
这种方法保证了构造出的数组满足美丽数组的所有条件。
代码实现
class Solution {
public:
vector<int> beautifulArray(int n) {
if (n == 1) return {1};
vector<int> odds = beautifulArray((n + 1) / 2);
vector<int> evens = beautifulArray(n / 2);
vector<int> result;
// 添加奇数部分 (2*x - 1)
for (int x : odds) {
result.push_back(2 * x - 1);
}
// 添加偶数部分 (2*x)
for (int x : evens) {
result.push_back(2 * x);
}
return result;
}
};
class Solution:
def beautifulArray(self, n: int) -> List[int]:
if n == 1:
return [1]
odds = self.beautifulArray((n + 1) // 2)
evens = self.beautifulArray(n // 2)
result = []
# 添加奇数部分 (2*x - 1)
for x in odds:
result.append(2 * x - 1)
# 添加偶数部分 (2*x)
for x in evens:
result.append(2 * x)
return result
public class Solution {
public int[] BeautifulArray(int n) {
if (n == 1) return new int[] {1};
int[] odds = BeautifulArray((n + 1) / 2);
int[] evens = BeautifulArray(n / 2);
int[] result = new int[n];
int index = 0;
// 添加奇数部分 (2*x - 1)
foreach (int x in odds) {
result[index++] = 2 * x - 1;
}
// 添加偶数部分 (2*x)
foreach (int x in evens) {
result[index++] = 2 * x;
}
return result;
}
}
/**
* @param {number} n
* @return {number[]}
*/
var beautifulArray = function(n) {
const memo = new Map();
function helper(n) {
if (memo.has(n)) return memo.get(n);
if (n === 1) return [1];
const odds = helper(Math.ceil(n / 2)).map(x => 2 * x - 1);
const evens = helper(Math.floor(n / 2)).map(x => 2 * x);
const result = odds.concat(evens);
memo.set(n, result);
return result;
}
return helper(n);
};
复杂度分析
| 复杂度类型 | 分析 |
|---|---|
| 时间复杂度 | O(n log n) - 递归深度为 log n,每层处理 O(n) 个元素 |
| 空间复杂度 | O(n log n) - 递归调用栈深度为 log n,每层存储 O(n) 空间 |