Leetcode659. 分割数组为连续子序列

Every day a Leetcode

题目来源:659. 分割数组为连续子序列

解法1:哈希 + 贪心

定义两个哈希表:

  • numsCount:统计数组 nums 中各元素出现次数。
  • tailCount:存储以数字 i 结尾的且符合题意的连续子序列个数。

算法:

  1. 先去寻找一个长度为3的连续子序列 i,i+1,i+2,找到后就将 numsCounti,numsCounti+1,numsCounti+2 中对应数字消耗 1 个(即 -1),并将 taili+2 加 1,即以 i+2 结尾的子序列个数 +1。
  2. 如果后续发现有能够接在这个连续子序列的数字 i+3,则延长以 i+2 为结尾的连续子序列到 i+3,此时消耗 numsCounti+3 一个,由于子序列已延长,因此 tailCounti+2 减 1,tailCounti+3 加 1。
  3. 在不满足上面的情况下:
    • 如果 numsCounti == 0,说明这个数字已经消耗完,可以不管了。
    • 如果 numsCounti != 0,说明这个数字多出来了,且无法组成连续子序列,直接返回 false。

因此,只有检查到某个数时,这个数未被消耗完,且既不能和前面组成连续子序列,也不能和后面组成连续子序列时,无法分割。

关于上面 1 和 2 的优先度,也就是说,当遇到一个新数,是新建一个长度为 3 的子序列好,还是补充到原有子序列的末尾好?

优先开新序列,不够贪,会丢失部分子序列尾的位置,而这可能造成丢解。

优先补前面更贪心,这种做法会覆盖优先开新序列时的尾的位置,补这补这总能到,补的过程中出现的尾位置也不会丢失。

代码:

c 复制代码
/*
 * @lc app=leetcode.cn id=659 lang=cpp
 *
 * [659] 分割数组为连续子序列
 */

// @lc code=start
class Solution
{
public:
    bool isPossible(vector<int> &nums)
    {
        if (nums.size() < 3)
            return false;
        unordered_map<int, int> numsCount, tailCount;
        // 统计数组 nums 中各元素出现次数
        for (int &num : nums)
            numsCount[num]++;
        // tailCount[i] 表示以 i 结尾的符合条件的子序列个数
        for (int &num : nums)
        {
            if (numsCount[num] == 0)
                continue;
            else if (numsCount[num] > 0 && tailCount[num - 1] > 0)
            {
                // 1. 补充到已有子序列的尾部
                numsCount[num] -= 1;
                tailCount[num - 1] -= 1;
                tailCount[num] += 1;
            }
            else if (numsCount[num] > 0 && numsCount[num + 1] > 0 && numsCount[num + 2] > 0)
            {
                // 2. 新建一条长度为 3 的子序列
                // 注意 1 的优先级比 2 高
                numsCount[num] -= 1;
                numsCount[num + 1] -= 1;
                numsCount[num + 2] -= 1;
                tailCount[num + 2] += 1;
            }
            else
                return false;
        }
        return true;
    }
};
// @lc code=end

结果:

复杂度分析:

时间复杂度:O(n),其中 n 是数组 nums 的长度。

空间复杂度:O(n),其中 n 是数组 nums 的长度。

相关推荐
MC皮蛋侠客8 小时前
C++17 多线程系列(五):C++17 并行算法——从串行到并行的零成本迁移
c++·多线程
_日拱一卒9 小时前
LeetCode:207课程表
java·数据结构·算法·leetcode·职场和发展
郭涤生12 小时前
C++ 高性能编程最佳实践清单
开发语言·c++
.千余12 小时前
【C++】C++类与对象2:C++构造函数、运算符重载与流输入输出全面解析
c语言·开发语言·前端·c++·经验分享
郭涤生12 小时前
C++ 高性能状态机
开发语言·c++
风筝在晴天搁浅13 小时前
美团 LeetCode 692.前K个高频单词
算法·leetcode·职场和发展
酿情师13 小时前
Microsoft Visual C++ Build Tools 2026 下载与安装指南(Windows)
c++·windows·microsoft
cany100013 小时前
C++ -- 引用悬挂
c++
.千余13 小时前
【C++】C++类与对象3:const成员函数与取地址运算符重载,权限管理的艺术
开发语言·c++
z2005093014 小时前
今日算法(回溯子集)(模版题)
数据结构·算法·leetcode