leetcode
leetcode 2501 ~ 2550
划分数组并满足最大差限制

划分数组并满足最大差限制

难度:

标签:

题目描述

You are given an integer array nums of size n and a positive integer k.

Divide the array into one or more arrays of size 3 satisfying the following conditions:

  • Each element of nums should be in exactly one array.
  • The difference between any two elements in one array is less than or equal to k.

Return a 2D array containing all the arrays. If it is impossible to satisfy the conditions, return an empty array. And if there are multiple answers, return any of them.

 

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.

 

Constraints:

  • n == nums.length
  • 1 <= n <= 105
  • n is a multiple of 3.
  • 1 <= nums[i] <= 105
  • 1 <= k <= 105

代码结果

运行时间: 112 ms, 内存: 31.7 MB


/*
 思路:
 1. 对数组进行排序。
 2. 使用Java Stream处理,尝试将每三个元素划分为一个子数组,并检查是否满足差值条件。
 3. 如果不能完全划分为符合条件的子数组,则返回空数组。
*/

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class Solution {
    public List<List<Integer>> partitionArray(int[] nums, int k) {
        Arrays.sort(nums);
        List<List<Integer>> result = IntStream.range(0, nums.length / 3)
            .mapToObj(i -> Arrays.asList(nums[i * 3], nums[i * 3 + 1], nums[i * 3 + 2]))
            .collect(Collectors.toList());
        for (List<Integer> group : result) {
            if (group.get(2) - group.get(0) > k) {
                return new ArrayList<>();
            }
        }
        return result;
    }
}

解释

方法:

该题解首先对数组进行排序,排序后的数组中相邻元素的差会是最小的。由于子数组的长度固定为3,题解采用了一个循环,步长为3,从排序后的数组中依次取出每3个元素组成子数组。在每次取出子数组时,检查子数组中的最大值和最小值的差是否大于k。如果大于k,则说明无法满足题目要求,直接返回空数组。如果所有子数组都满足条件,则将这些子数组返回。这种方法使用了贪心的策略,即尽可能地将排序后相邻的元素分配到同一个子数组中,利用排序后元素间差值最小的特性来满足差值条件。

时间复杂度:

O(n log n)

空间复杂度:

O(log n)

代码细节讲解

🦆
为什么选择将输入数组进行排序是处理这个问题的首要步骤?
排序是处理这个问题的首要步骤,因为排序后相邻元素的差值会最小,这有助于最大限度地减小子数组内的最大值与最小值的差值。这种方法使得在进行子数组分割时,可以较容易地满足最大差值不超过k的条件。如果数组未排序,相邻元素的差值可能很大,难以控制子数组内的最大差值,从而影响整体的分割策略。
🦆
在检查子数组中的最大值和最小值的差时,是否存在一种情况,即使当前子数组满足条件,但是后续的子数组因为重新分配而无法满足条件?
在本题解策略中,由于数组已经排序并且以固定步长3来划分子数组,每个子数组内部的元素是连续的三个元素。因此,如果一个子数组满足最大值与最小值的差不超过k,后续的子数组也会独立地进行检查。这里不存在因前一个子数组的分配而影响到后续子数组的情况,因为子数组的分配是基于排序后的固定位置,不依赖于其他子数组的配置。
🦆
在代码中,如果数组长度不是3的倍数,即`n % 3 != 0`,该如何处理?算法中似乎没有显式处理这种情况。
题解中没有显式处理数组长度不是3的倍数的情况,这是一个缺陷。在实际应用中,应该在循环遍历数组之前检查数组长度是否为3的倍数。如果不是,应该返回一个错误或者空数组,因为题目要求子数组长度固定为3,如果无法完全分割成多个长度为3的子数组,则无法满足题目的要求。
🦆
题解中提到使用贪心策略,能否解释一下为什么这种贪心方法在本题中是有效的?
本题的贪心策略在于尽可能利用排序后相邻元素之间差值最小的特性,通过固定步长(本例为3)选择连续的元素来形成子数组。这种方法有效,因为在已排序的数组中,连续的几个元素之间的最大差值通常比非连续元素的差值小,从而更有可能满足差值不大于k的条件。这种策略简化了问题,避免了复杂的子数组重组和重新计算差值的需要,提高了算法的效率和实现的简洁性。

相关问题