leetcode
leetcode 2701 ~ 2750
修改数组后最大化数组中的连续元素数目

修改数组后最大化数组中的连续元素数目

难度:

标签:

题目描述

You are given a 0-indexed array nums consisting of positive integers.

Initially, you can increase the value of any element in the array by at most 1.

After that, you need to select one or more elements from the final array such that those elements are consecutive when sorted in increasing order. For example, the elements [3, 4, 5] are consecutive while [3, 4, 6] and [1, 1, 2, 3] are not.

Return the maximum number of elements that you can select.

 

Example 1:

Input: nums = [2,1,5,1,1]
Output: 3
Explanation: We can increase the elements at indices 0 and 3. The resulting array is nums = [3,1,5,2,1].
We select the elements [3,1,5,2,1] and we sort them to obtain [1,2,3], which are consecutive.
It can be shown that we cannot select more than 3 consecutive elements.

Example 2:

Input: nums = [1,4,7,10]
Output: 1
Explanation: The maximum consecutive elements that we can select is 1.

 

Constraints:

  • 1 <= nums.length <= 105
  • 1 <= nums[i] <= 106

代码结果

运行时间: 162 ms, 内存: 26.9 MB


/*
 * 思路:
 * 1. 使用流处理遍历数组并计算每个元素增加1后的频率。
 * 2. 对所有可能的元素进行计数,并使用滑动窗口来找到最大连续元素的数量。
 */
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class Solution {
    public int maxContinuousElements(int[] nums) {
        Map<Integer, Long> frequencyMap = IntStream.concat(IntStream.of(nums), IntStream.of(nums).map(num -> num + 1))
                .boxed()
                .collect(Collectors.groupingBy(num -> num, Collectors.counting()));
        int maxCount = 0;
        int currentCount = 0;
        for (int key : frequencyMap.keySet()) {
            if (frequencyMap.containsKey(key - 1)) {
                currentCount += frequencyMap.get(key);
            } else {
                currentCount = frequencyMap.get(key).intValue();
            }
            maxCount = Math.max(maxCount, currentCount);
        }
        return maxCount;
    }
}

解释

方法:

此题解使用排序加动态规划的方法来解决问题。首先将数组排序,然后使用两个变量 highLength 和 lowLength 来跟踪可以构成的连续子序列的最大长度。highLength 记录不需要增加的连续子序列的长度,而 lowLength 则考虑可以通过增加 1 的方式延伸的子序列的长度。通过迭代排序后的数组,根据当前数与前一个数的关系更新 highLength 和 lowLength,并在每步中更新最大长度 ans。当当前数等于前一个数加一时,这两个长度都增加。如果当前数等于前一个数加二,说明可以通过增加 1 形成新的序列,此时更新 highLength。如果两者差距超过 2,重置这两个长度。这种方法通过一次遍历就能找到可能的最大连续子序列长度。

时间复杂度:

O(n log n)

空间复杂度:

O(n)

代码细节讲解

🦆
为什么在算法中选择排序数组作为第一步,而不是直接在未排序的数组上进行操作?
在未排序的数组中,数字的顺序是随机的,这使得直接检测数字之间的连续性或差距非常困难,因为我们必须不断地检查数组中的每个数字来找到可能的连续序列。通过首先对数组进行排序,我们能够保证所有数字都是按照递增顺序排列的。这样,我们只需要按顺序遍历一次数组,就可以有效地检查每个数字与前一个数字之间的关系,从而判断能否形成或延伸连续子序列,或者是否需要重置序列长度。排序简化了问题的复杂性,并且提高了算法的效率。
🦆
你是如何确定两个连续数字之间可以通过增加1来填补的,而不是通过增加更多的数字?
当两个数字之间的差为2时,意味着它们之间正好缺少一个数字,我们可以通过增加这一个缺失的数字来构成连续序列。例如,如果有数字4和6,它们之间差2,那么我们可以增加数字5来使这三个数字构成一个连续序列。如果两数字之间的差大于2,那么意味着缺少的不仅仅是一个数字,增加更多的数字会使问题变得复杂,并且在题目设定中可能不允许随意增加过多的数字。因此,算法只考虑通过增加一个数字来填补的情况。
🦆
在处理数字之间的差距大于2的情况时,为什么选择重置连续长度计数器 highLength 和 lowLength?
当数字之间的差距大于2时,说明在这两个数字之间缺少至少两个数字,因此它们之间无法构成连续序列,也不能通过简单地增加一个数字来连接。在这种情况下,之前跟踪的连续子序列已经无法继续延伸,因此必须重新开始计算新的连续子序列的长度。重置 highLength 和 lowLength 使我们可以从当前数字开始,尝试构建新的连续子序列,而不是错误地将之前的非连续数字纳入计算。这样做可以确保我们始终跟踪的是有效的连续序列长度。

相关问题