LeetCode #659 Split Array into Consecutive Subsequences

本文介绍了一种算法,用于判断是否可以将已排序的整数数组分割成多个连续子序列,每个子序列至少包含3个连续整数。通过两次遍历数组,使用哈希表记录数字频率和连续序列尾部数字的数量,最终确定能否完成分割。

题目

You are given an integer array sorted in ascending order (may contain duplicates), you need to split them into several subsequences, where each subsequences consist of at least 3 consecutive integers. Return whether you can make such a split.
Example 1:

Input: [1,2,3,3,4,5]
Output: True
Explanation:
You can split them into two consecutive subsequences : 
1, 2, 3
3, 4, 5

Example 2:

Input: [1,2,3,3,4,4,5,5]
Output: True
Explanation:
You can split them into two consecutive subsequences : 
1, 2, 3, 4, 5
3, 4, 5

Example 3:

Input: [1,2,3,4,4,5]
Output: False

Note:

  1. The length of the input is in range of [1, 10000]

解题思路

刚开始的时候老是想着在扫描数组时,每扫描到一个新的数字都要确定以该数字为开头的一个连续序列。其实根本不需要扫到一个数字就确定一个连续序列,而是可以在扫描数组的过程中,把数字逐一地添加到未完整的连续序列中,动态地往连续序列中添加数据。整个算法过程如下:

  1. 维护两个哈希表 frequencytails. frequency 表记录数组中每个数字出现的次数,而 tails 表则记录以某个数字结尾的连续序列的个数,比如 tails[key] 的值为2,表示以数字 key 为结尾的连续序列共有两个。

  2. 第一次扫描数组,把数组中每个数字的出现次数记录到 frequency 表中。

  3. 第二次扫描数组,对扫描到的每一个数字 num,如果 tails[num - 1] > 0 ,说明存在以 num - 1 为结尾的连续序列,则把数字 num 添加到该连续序列中:tails[num - 1]--; tails[num]++。可能有人会担心 num可能是另一个连续序列的开始数字而不应该加入到 tails[num - 1] 的连续序列中,但是任意以 num 为开始数组的连续序列都可以与 tails[num - 1] 的连续序列合并:比如 [1, 2, 3][4, 5, 6] 两个连续序列是可以合并成 [1, 2, 3, 4, 5, 6] 这个大的连续序列的,这对于结果是没有影响的;如果 tails[num - 1] == 0 ,此时我们就需要以 num 为开始数字建立一个新的连续序列。而一个连续序列至少包含 3 个数字,因此还要检查 num + 1num + 2 这两个数字是否存在,如果不存在,则直接 return false ,否则,新建以 num + 2 数字为结尾的连续序列。

  4. 如果上述过程能进行到最后,说明所有连续序列都能够找出来,则直接 return true

C++代码实现

class Solution {
public:
    bool isPossible(vector<int>& nums) {
        unordered_map<int, int> frequency, tails;

        for (int &num : nums) { frequency[num]++; }
        for (int &num : nums) {
            // 如果 frequency[num] <= 0,说明在上一轮循环中新建了
            // 一个包含当前数字 num 的连续序列,直接跳过扫描下一个数字
            if (frequency[num] <= 0) { continue; }
            frequency[num]--;

            if (tails[num - 1] > 0) {
                tails[num - 1]--;
                tails[num]++;
            } else if (frequency[num + 1] && frequency[num + 2]) {
                // 新建连续序列,要把包含进新序列的数字的出现次数也减 1
                frequency[num + 1]--;
                frequency[num + 2]--;
                tails[num + 2]++;
            } else {
                return false;
            }
        }

        return true;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值