Medium
题目描述
给你一个长度为 n 的整数数组 nums,其中 n 是 3 的倍数,以及一个正整数 k。
将数组 nums 分成 n / 3 个长度为 3 的数组,满足以下条件:
- 每个数组中任意两个元素的差值小于或等于
k。
返回一个包含这些数组的二维数组。如果无法满足条件,返回一个空数组。如果有多个答案,返回其中任意一个。
示例 1:
输入:nums = [1,3,4,8,7,9,3,5,1], k = 2
输出:[[1,1,3],[3,4,5],[7,8,9]]
解释:每个数组中任意两个元素的差值都小于或等于 2。
示例 2:
输入:nums = [2,4,2,2,5,2], k = 2
输出:[]
解释:将 nums 分成 2 个长度为 3 的数组的不同方法有:
[[2,2,2],[2,4,5]](及其排列)
[[2,2,4],[2,2,5]](及其排列)
因为有四个 2,无论如何分割都会有一个数组包含元素 2 和 5。
由于 5 - 2 = 3 > k,不满足条件,所以没有有效的分割。
示例 3:
输入:nums = [4,2,9,8,2,12,7,12,10,5,8,5,5,7,9,2,5,11], k = 14
输出:[[2,2,2],[4,5,5],[5,5,7],[7,8,8],[9,9,10],[11,12,12]]
解释:每个数组中任意两个元素的差值都小于或等于 14。
提示:
n == nums.length1 <= n <= 10^5n是 3 的倍数1 <= nums[i] <= 10^51 <= k <= 10^5
解题思路
这道题使用贪心算法求解。核心思路是:先排序,然后将相邻的三个元素分为一组。
分析过程:
排序的必要性:为了使每组内元素差值尽可能小,我们需要将数组排序,这样相邻元素的差值最小。
贪心策略:排序后,贪心地将每连续的3个元素分为一组。如果一组中最大值和最小值的差超过k,说明无解。
正确性证明:
- 对于排序后的数组,如果
a ≤ b ≤ c是连续的三个元素,那么c - a是这三个元素中任意两个的最大差值 - 如果连续三个元素无法满足条件,那么任何其他分组方式都不可能更优
- 对于排序后的数组,如果
算法步骤:
- 对数组排序
- 每次取3个连续元素作为一组
- 检查每组的最大差值是否 ≤ k
- 如果所有组都满足条件,返回结果;否则返回空数组
时间复杂度:O(n log n),主要是排序的复杂度 空间复杂度:O(1),不考虑输出空间的话
代码实现
class Solution {
public:
vector<vector<int>> divideArray(vector<int>& nums, int k) {
sort(nums.begin(), nums.end());
vector<vector<int>> result;
int n = nums.size();
for (int i = 0; i < n; i += 3) {
if (nums[i + 2] - nums[i] > k) {
return {};
}
result.push_back({nums[i], nums[i + 1], nums[i + 2]});
}
return result;
}
};
class Solution:
def divideArray(self, nums: List[int], k: int) -> List[List[int]]:
nums.sort()
result = []
n = len(nums)
for i in range(0, n, 3):
if nums[i + 2] - nums[i] > k:
return []
result.append([nums[i], nums[i + 1], nums[i + 2]])
return result
public class Solution {
public int[][] DivideArray(int[] nums, int k) {
Array.Sort(nums);
var result = new List<int[]>();
int n = nums.Length;
for (int i = 0; i < n; i += 3) {
if (nums[i + 2] - nums[i] > k) {
return new int[0][];
}
result.Add(new int[] {nums[i], nums[i + 1], nums[i + 2]});
}
return result.ToArray();
}
}
var divideArray = function(nums, k) {
nums.sort((a, b) => a - b);
const result = [];
const n = nums.length;
for (let i = 0; i < n; i += 3) {
if (nums[i + 2] - nums[i] > k) {
return [];
}
result.push([nums[i], nums[i + 1], nums[i + 2]]);
}
return result;
};
复杂度分析
| 复杂度类型 | 复杂度 | 说明 |
|---|---|---|
| 时间复杂度 | O(n log n) | 主要是排序的时间复杂度,遍历数组的时间为 O(n) |
| 空间复杂度 | O(1) | 不考虑输出空间,只使用了常数级别的额外空间 |