[Leetcode]667.Beautiful Arrangement II
链接:LeetCode667
给定两个整数?n?和?k,你需要实现一个数组,这个数组包含从?1?到?n?的 n?个不同整数,同时满足以下条件:
① 如果这个数组是\([a1, a2, a3, ... , an]\),那么数组\([|a1 - a2|, |a2 - a3|, |a3 - a4|, ... , |an-1 - an|]\)中应该有且仅有?k 个不同整数;.
② 如果存在多种答案,你只需实现并返回其中任意一种.
示例 1:
输入: n = 3, k = 1
输出: \([1, 2, 3]\)
解释: \([1, 2, 3]\) 包含 3 个范围在 1-3 的不同整数, 并且 \([1, 1]\) 中有且仅有 1 个不同整数 : 1
这道题真实诠释了什么是思考一小时,解题一分钟。遇到这种题,明显无法通过数据结构和常用的算法技巧来解,我们需要通过多次尝试,找规律才能发现解法。我们用一个例子来分析,比如说当n=8,我们有数组:
1, 2, 3, 4, 5, 6, 7, 8
当我们这样有序排列的话,相邻两数的差的绝对值为1。我们想差的绝对值最大能为多少,应该是把1和8放到一起,为7。那么为了尽可能的产生不同的差的绝对值,我们在8后面需要放一个小数字,比如2,这样会产生差的绝对值6,同理,后面再跟一个大数,比如7,产生差的绝对值5,以此类推,我们得到下列数组:
1, 8, 2, 7, 3, 6, 4, 5
其差的绝对值为:7,6,5,4,3,2,1
共有7种,所以我们知道k最大为n-1,所以这样的排列一定会存在。我们的策略是,先按照这种最小最大数相邻的方法排列,没排一个,k自减1,当k减到1的时候,后面的排列方法只要按照生序的方法排列,就不会产生不同的差的绝对值,这种算法的时间复杂度是O(n),属于比较高效的那种。我们使用两个指针,初始时分别指向1和n,然后分别从i和j取数加入结果res,每取一个数字k自减1,直到k减到1的时候,开始按升序取后面的数字。
另外,还有一种解法是将数组不停翻转即可。代码如下:
python:
class Solution: def constructArray(self, n: int, k: int) -> List[int]: nums = list(range(1,n+1)) for i in range(k): nums[i:] = nums[i:][::-1] return nums
C++:
class Solution { public: vector<int> constructArray(int n,int k){ vector<int> res; int i=1,j=n; while(i<=j){ if(k>1) res.push_back(k--%2 ? i++ : j--); else res.push_back(i++); } return res; } vector<int> constructArray2(int n, int k) { vector<int> nums; for(int i=1;i<=n;++i){ nums.push_back(i); } for(int i=0;i<k;++i){ reverse(nums.begin()+i,nums.end()); } return nums; } };