leetcode
leetcode 2001 ~ 2050
划分数组使最大差为 K

划分数组使最大差为 K

难度:

标签:

题目描述

代码结果

运行时间: 103 ms, 内存: 30.6 MB


/* 
题目思路:
1. 对数组进行排序。
2. 使用Stream API来进行数组的遍历和处理。
3. 初始化一个变量用于记录子序列的数量。
4. 遍历排序后的数组,使用一个指针指向当前子序列的开始位置。
5. 对于每一个新的元素,如果它与当前子序列的最小元素的差值超过k,则创建一个新的子序列。
6. 返回子序列的数量。
*/

import java.util.Arrays;

public class Solution {
    public int minSubsequences(int[] nums, int k) {
        Arrays.sort(nums);
        final int[] count = {1};
        final int[] start = {0};

        Arrays.stream(nums).skip(1).forEach(num -> {
            if (num - nums[start[0]] > k) {
                count[0]++;
                start[0] = Arrays.binarySearch(nums, num);
            }
        });

        return count[0];
    }

    public static void main(String[] args) {
        Solution solution = new Solution();
        int[] nums = {3, 6, 1, 2, 5};
        int k = 2;
        System.out.println(solution.minSubsequences(nums, k)); // 输出:2
    }
}

解释

方法:

首先,题解通过转换列表为集合来去除任何重复元素,因为重复元素可以放在同一个子序列中而不影响最大值和最小值的差。然后,对去重后的数组进行排序,便于顺序比较元素。题解采用贪心算法的思想,从第一个元素开始,依次判断后一个元素与当前子序列最小元素的差是否大于k。如果大于k,意味着需要开始一个新的子序列,并将当前元素设为新子序列的最小元素;如果不大于k,则当前元素可以加入到当前子序列。通过遍历一次数组,可以确定需要的最少子序列数。

时间复杂度:

O(n log n)

空间复杂度:

O(n)

代码细节讲解

🦆
为什么在处理前先将数组转换为集合再转回列表?这一转换对子序列的划分有什么影响?
将数组转换为集合的主要目的是去除数组中的所有重复元素。在本题的上下文中,重复元素不会对子序列中的最大值和最小值产生影响,因为它们相同,所以其差值为零,不会超过k。通过移除重复项,可以简化问题规模并防止在计算子序列时重复考虑相同的值。这样不仅减少了计算量,而且使得问题变得更加清晰,只需考虑不重复的数字,从而在划分子序列时更加高效。
🦆
在算法中,为什么选择排序后的数组来进行子序列的划分?直接在未排序的数组上操作是否可行?
在算法中使用排序后的数组是为了方便管理和判断子序列的建立。通过排序,可以保证遍历数组时,元素是按照从小到大的顺序处理的。这样做可以轻松判断当前元素是否可以加入已有的子序列或者是否需要开始一个新的子序列。如果直接在未排序的数组上操作,虽然理论上也可行,但会大幅增加算法的复杂度和实现难度,因为需要不断调整和记录多个同时活跃的子序列的状态,这在实践中是不易管理的。
🦆
题解中提到,如果当前元素与子序列的最小元素的差大于 k,则需要开始一个新的子序列。请问这种方法是否能保证总是得到最少的子序列数目?
是的,这种方法能保证总是得到最少的子序列数目。这是因为算法通过贪心的策略,在每一步都尽可能的将元素加入到当前的子序列中,只有当当前元素与子序列的最小值的差大于k时才开始新的子序列。这确保每个子序列包含的元素是按照最小可能的差分布的,因此在满足差值条件的前提下,不会过早地开始新的子序列,从而达到使用最少子序列数的目的。
🦆
在算法实现中,变量 `pre` 是如何使用的,它的作用是什么?
在算法实现中,`pre` 变量用于记录当前子序列的起始元素(或最小元素)。它在算法开始时初始化为数组的第一个元素,然后在遍历过程中,每当确定需要开始一个新的子序列时,`pre` 将被更新为当前考虑的元素。这样,`pre` 始终保持为当前活跃子序列的最小值,用于与后续的元素比较,以决定是否需要开始一个新的子序列。因此,`pre` 是实现贪心策略的关键变量,帮助跟踪和管理子序列的分界。

相关问题