LeetCode #659 Split Array into Consecutive Subsequences

题目

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、付费专栏及课程。

余额充值