这两天比较忙,之后如果有时间会慢慢补拉下的题目。
题目要求
给你一个大小为 n 的整数数组 nums 和一个正整数 k。
将数组划分为一个或多个大小为 3 的数组,并满足以下条件:
- 数组 nums 中的每个元素都应恰好位于一个数组中。
- 一个数组中任意两个元素之差小于或等于 k。
- 返回一个包含所有数组的 2D 数组。如果无法满足条件,则返回空数组。如果有多个答案,则返回其中任意一个。
Example 1:
Input: nums = [1,3,4,8,7,9,3,5,1], k = 2 Output: [[1,1,3],[3,4,5],[7,8,9]] Explanation: We can divide the array into the following arrays: [1,1,3], [3,4,5] and [7,8,9]. The difference between any two elements in each array is less than or equal to 2. Note that the order of elements is not important.
Example 2:
Input: nums = [1,3,3,2,7,3], k = 3 Output: [] Explanation: It is not possible to divide the array satisfying all the conditions.
思路
首先仔细看题目中的要求,每个数字在子数列中出现恰好1次,同时n一定是3的倍数。那么我们就不需要考虑重复值、复杂判断的问题了,给每个数字安排他们的位置即可。
那么想到我们需要首先对数组进行排序,因为数组经过排序后相邻元素的差值最小。这意味着如果排序后的数组中存在任何相邻元素之间的差值大于k,那么将这些元素分配到满足条件的大小为3的子数组中就不可能了。反过来,如果排序后的数组中所有相邻元素的差值都不大于k,那么我们就可以三个一组的构建数组了。
那么我们梳理一下步骤:
- 对原始数组进行排序。(如果原始数组为空,则不可能组成子数组。)
- 首先子数组为空,每次对子数组加入元素的时候判断,加入新的元素是否会破坏差值最大为k的结构。如果破坏则直接返回false,因为我们已经排序,当前num不行,后续num也不行。
- 如果当前子数组的长度为3,push_back进入result成为一个解,然后temp.clear()清理当前子数组。
代码
class Solution {
public:
bool check_diff(vector<int>& temp, int num, int k) {
if (temp.empty() || abs(temp[0] - num) <= k && abs(temp.back() - num) <= k) {
return true;
}
return false;
}
vector<vector<int>> divideArray(vector<int>& nums, int k) {
if (nums.size() < 3) {
return vector<vector<int>>();
}
sort(nums.begin(), nums.end());
vector<int> temp;
vector<vector<int>> result;
for (int num : nums) {
if (temp.size() < 3) {
if (check_diff(temp, num, k)) {
temp.push_back(num);
} else {
return vector<vector<int>>();
}
}
if (temp.size() == 3) {
result.push_back(temp);
temp.clear();
}
}
return result;
}
};
排序时间复杂度O(nlogn),遍历数组O(n),总体时间复杂度O(nlogn)。空间上创建二维数组存储result,复杂度O(n)。