leetcode
leetcode 551 ~ 600
分割数组为连续子序列

分割数组为连续子序列

难度:

标签:

题目描述

代码结果

运行时间: 75 ms, 内存: 16.8 MB


/*
 * 题目思路:
 * 1. 使用 Java Stream 对输入数组进行处理。
 * 2. 统计每个数字的出现次数。
 * 3. 使用 Stream API 的特性来处理子序列的添加和创建。
 */
 
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
 
public class SplitArrayIntoSubsequencesStream {
    public boolean isPossible(int[] nums) {
        Map<Integer, Long> freq = IntStream.of(nums).boxed()
                .collect(Collectors.groupingBy(n -> n, Collectors.counting()));
        Map<Integer, Long> appendFreq = new HashMap<>();
 
        for (int num : nums) {
            if (freq.get(num) == 0) continue;
 
            if (appendFreq.getOrDefault(num, 0L) > 0) {
                appendFreq.put(num, appendFreq.get(num) - 1);
                appendFreq.put(num + 1, appendFreq.getOrDefault(num + 1, 0L) + 1);
            } else if (freq.getOrDefault(num + 1, 0L) > 0 && freq.getOrDefault(num + 2, 0L) > 0) {
                freq.put(num + 1, freq.get(num + 1) - 1);
                freq.put(num + 2, freq.get(num + 2) - 1);
                appendFreq.put(num + 3, appendFreq.getOrDefault(num + 3, 0L) + 1);
            } else {
                return false;
            }
 
            freq.put(num, freq.get(num) - 1);
        }
 
        return true;
    }
}

解释

方法:

这个题解使用贪心算法和哈希表来判断能否将数组分割成满足条件的子序列。主要思路如下: 1. 先用一个哈希表count统计每个数字出现的次数 2. 再用一个哈希表tail记录以每个数字结尾的子序列个数 3. 遍历数组,对于每个数字n: - 如果n-1结尾的子序列个数大于0,则将n加入n-1结尾的子序列中 - 否则,如果n+1和n+2的计数都大于0,则将n, n+1, n+2作为新的子序列 - 如果上述两种情况都不满足,说明无法构成满足条件的分割,返回false 4. 遍历结束后,说明可以进行满足条件的分割,返回true

时间复杂度:

O(n)

空间复杂度:

O(n)

代码细节讲解

🦆
为什么在判断是否可以将数字n加入到以n-1结尾的子序列中时,不需要检查以n-1结尾的子序列长度是否至少为3?
在算法执行过程中,当我们考虑将数字n加入到以n-1结尾的子序列时,我们不需要检查该子序列的长度是否至少为3,因为只要存在以n-1结尾的子序列,它的形成肯定已经符合了题目要求的最小长度3(或已经在此基础上扩展)。这是因为任何有效子序列在加入新元素之前,必须已经是一个有效的子序列。因此,我们只需关注是否存在以n-1结尾的子序列,而不需检查其具体长度。
🦆
在创建新子序列时,为什么选择的是n, n+1, n+2这三个连续数字,是否有其他数字组合可能以及为什么不使用这些组合?
在创建新的子序列时,选择n, n+1, n+2这三个连续数字是因为这样可以确保子序列的连续性且满足题目要求的最小长度3。如果选择了比n+2更大的数字,那么子序列中间会存在间断,不符合连续子序列的要求。如果选择长度小于3的子序列或不连续的数字,都将无法满足题目对连续子序列的定义。因此,n, n+1, n+2是构建符合题目要求的最基本、最简单的连续子序列的方式。
🦆
如果在处理过程中,n+1或n+2的count为0,但后面的数字中有可用的n+1和n+2,这种情况下如何处理以保证最优的子序列分割?
如果在处理某个数字n时,n+1或n+2的count为0,即这两个数字不能立即用来形成新的子序列,那么我们不能以n开始一个新的子序列。算法应继续向后查找,直到找到一个可以形成新子序列的位置,即找到一个新的n,其中n, n+1, n+2的count都大于0。这种延迟决策的方法有助于避免提前消耗数字,从而更灵活地应对后面的数字,保证了算法的贪心策略能够尽可能多地形成有效的子序列。
🦆
算法中提到如果无法生成满足条件的子序列则返回false,能否具体说明哪些情况下会发生这种无法生成的情况?
在算法执行过程中,如果某个数字n无法被加入到任何现有的子序列,并且也无法与其后的数字n+1和n+2一起形成一个新的子序列,那么算法将返回false。这种情况通常发生在以下几种情况:1) 当前数字n的后续数字n+1或n+2不存在或者它们的计数已经为0,使得无法形成新的连续子序列;2) 当前数字n也不能加入任何以n-1结尾的子序列,因为不存在这样的子序列。这两种情况表明,无法继续形成或扩展子序列,从而无法满足题目的要求。

相关问题

前 K 个高频元素

给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。

 

示例 1:

输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]

示例 2:

输入: nums = [1], k = 1
输出: [1]

 

提示:

  • 1 <= nums.length <= 105
  • k 的取值范围是 [1, 数组中不相同的元素的个数]
  • 题目数据保证答案唯一,换句话说,数组中前 k 个高频元素的集合是唯一的

 

进阶:你所设计算法的时间复杂度 必须 优于 O(n log n) ,其中 n 是数组大小。