Description
Given two integers n
and k
, you need to construct a list which contains n
different positive integers ranging from 1
to n
and obeys the following requirement:
Suppose this list is [a1, a2, a3, ... , an], then the list [|a1 - a2|, |a2 - a3|, |a3 - a4|, ... , |an-1 - an|] has exactly k
distinct integers.
If there are multiple answers, print any of them.
Example 1:
Input: n = 3, k = 1
Output: [1, 2, 3]
Explanation: The [1, 2, 3] has three different positive integers ranging from 1 to 3, and the [1, 1] has exactly 1 distinct integer: 1.
Example 2:
Input: n = 3, k = 2
Output: [1, 3, 2]
Explanation: The [1, 3, 2] has three different positive integers ranging from 1 to 3, and the [2, 1] has exactly 2 distinct integers: 1 and 2.
Note:
- The
n
andk
are in the range 1 <= k < n <= 104.
Solution
Backtracking, O(n ^ 2), S(n) (TLE)
典型的回溯思路。
class Solution {
public int[] constructArray(int n, int k) {
int[] nums = new int[n];
for (int i = 0; i < n; ++i) {
nums[i] = i + 1;
}
backtracking(nums, 0, new int[n], 0, k);
return nums;
}
private boolean backtracking(int[] nums, int start, int[] counts, int unique, int k) {
if (start >= nums.length && unique == k) {
return true;
}
if (unique >= k) {
return false;
}
for (int i = start; i < nums.length; ++i) {
swap(nums, start, i);
if (start > 0) {
int delta = Math.abs(nums[start] - nums[start - 1]);
if (++counts[delta] == 1) {
++unique;
}
}
if (backtracking(nums, start + 1, counts, unique, k)) {
return true;
}
if (start > 0) {
int delta = Math.abs(nums[start] - nums[start - 1]);
if (--counts[delta] == 0) {
--unique;
}
}
swap(nums, start, i);
}
return false;
}
private void swap(int[] nums, int i, int j) {
int tmp = nums[i];
nums[i] = nums[j];
nums[j] = tmp;
}
}
Construct, O(n), S(1)
这道题的解法其实是有规律可循的:
- k = 1: 序列为{1, 2, ..., n - 1, n}
- k = n - 1: 序列为{1, n, 2, n - 1, ..., n / 2 - 1, n / 2},这样delta就是{n-1, n-2, n-3, ..., 1},unique count = n - 1
对n个数字来说,可以构成最少1个最多n - 1个unique delta的序列。
那么如果想要生成unique number为k的n个数序列,把数字分成两部分即可:
- part 1: n - k - 1个数字:{1, 2, ..., n - k - 1}
- part 2: k + 1个数字:{1, k, 2, k - 1, ..., k / 2 - 1, k / 2},所有数字再加上初始的increase为n - k - 1。这部分序列生成,要依靠头尾拼接数组来做。
然后将两部分拼接起来,返回即可。
class Solution {
public int[] constructArray(int n, int k) {
int[] nums = new int[n];
int pos = 0;
for (int i = 1; i < n - k; ++i) {
nums[pos++] = i;
}
for (int i = 0; i <= k; ++i) {
nums[pos++] = i % 2 == 0 ?
i / 2 + n - k : n - i / 2;
}
return nums;
}
}