一、题目
给你两个整数 n
和 k
,请你构造一个答案列表 answer
,该列表应当包含从 1
到 n
的 n 个不同正整数,并同时满足下述条件:
假设该列表是 answer = [a1, a2, a3, ... , an]
,那么列表 [|a1 - a2|, |a2 - a3|, |a3 - a4|, ... , |an-1 - an|]
中应该有且仅有 k
个不同整数。
返回列表 answer
。如果存在多种答案,只需返回其中 任意一种 。
二、示例
2.1> 示例 1:
【输入】n = 3, k = 1
【输出】[1, 2, 3]
【解释】[1, 2, 3] 包含 3 个范围在 1-3 的不同整数,并且 [1, 1] 中有且仅有 1 个不同整数:1
2.2> 示例 2:
【输入】n = 3, k = 2
【输出】[1, 3, 2]
【解释】[1, 3, 2] 包含 3 个范围在 1-3 的不同整数,并且 [2, 1] 中有且仅有 2 个不同整数:1 和 2
提示:
1
<= k < n <=10^4
三、解题思路
根据题目描述,方法入参由两个参数,第一个参数是n,我们可以得到一个数组[1, 2, 3, 4, ... , n]
。第二个参数是k,表示当我们遍历数组,计算相邻两个元素的差值(取绝对值)的时候,有且仅有k个不同的整数。那么,针对这个数组,差值一共能有多少种情况呢?我们以下图为例,给出一个数组[1, 2, 3, 4, 5, 6]
,我们发现,一共能获得5中不同的差值。那么,我们其实可以得出一个结论,一个长度为n的数组,其差值就在[1, n-1]
的区间内,详情如下图所示:
我们得出如下结论之后,那么,下面步骤,就是要根据k的值,具体安排这n个数在数组中的位置了。我们以n=6,k=3为例
。首先,因为1是数组中最小的值。所以我们将数组中第一位的值赋值为1
,然后我们根据以1为基准,在去安排其他值。
确定了数组中第一个值为1之后,我们来安排一下其他元素,根据第一张图,我们可以得知,如果数组中的元素是按照顺序排列的话,每个相邻节点的差值就是1,所以,这就是我们得出的第1个差值。那么针对于第二个参数k值。我们就可以将整个数组分为两部分排列:无顺序排列 + 有顺序排列。类似如下这种情况:
所以,我们先来看一下无顺序排列的情况,我们的目的,是要拼装出k-1
种差值。这种情况的拼装方式就需要一个interval变量了。它表示要“跳跃”的区间,最初我们可以将其赋值为k的值,即:interval = k;由于k等于3,所以interval=3
。首先,我们要先向前跳跃3个区间,即:4,这个值就是我们数组中的第二个值,并且,由于我们需要不同的差值,此时interval要减1,即:interval=2
。然后,我们要向后跳跃2个区间,即:2,这个值就是我们数组中的第三个值。一次类推。最终,我们得到数组[1, 4, 2, 3, ...]。此时的差值为:3,2,1。即:满足了k=3的约束了。
那么,在最后,我们只需要将有序排列的数组构建出来就可以了。由于跳跃区间interval我们初始化为k,并且上面只构建了数组中前k+1个元素的,这里面除去1之外最小值为:minValue = 2
,最大值为:maxValue = k + 1
。而我们当前的下标是i,i = maxValue + 1;所以假设answer[i]=i,则answer[i]与minValue的差值等于 (maxValue + 1) - 2 = ( k + 1 + 1) - 2 = k
。而k值已经包含在了前[0, i -1]的数组区间内了。那么,我们就可以直接通过answer[i] = i + 1去构造有序排列了。如下所示:
四、代码实现
class Solution {
public int[] constructArray(int n, int k) {
int interval = k;
int[] answer = new int[n];
answer[0] = 1;
for (int i = 1; i <= k; i++) {
answer[i] = i % 2 == 1 ? answer[i - 1] + interval : answer[i - 1] - interval;
interval--;
}
for (int i = k + 1; i < n; i++) {
answer[i] = i + 1;
}
return answer;
}
}
今天的文章内容就这些了:
写作不易,笔者几个小时甚至数天完成的一篇文章,只愿换来您几秒钟的 点赞 & 分享 。
更多技术干货,欢迎大家关注公众号“爪哇缪斯” ~ \(^o^)/ ~ 「干货分享,每天更新」