夯实算法-分割数组为连续子序列

131 阅读1分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 26 天,点击查看活动详情

题目:LeetCode

给你一个按 非递减顺序 排列的整数数组 nums 。

请你判断是否能在将 nums 分割成 一个或多个子序列 的同时满足下述 两个 条件:

  • 每个子序列都是一个 连续递增序列(即,每个整数 恰好 比前一个整数大 1 )。
  • 所有子序列的长度 至少 为 3 ****。

如果可以分割 nums 并满足上述条件,则返回 true ;否则,返回 false 。

示例 1:

输入: nums = [1,2,3,3,4,5]
输出: true
解释: nums 可以分割成以下子序列:
[1,2,3,3,4,5] --> 1, 2, 3
[1,2,3,3,4,5] --> 3, 4, 5

示例 2:

输入: nums = [1,2,3,3,4,4,5,5]
输出: true
解释: nums 可以分割成以下子序列:
[1,2,3,3,4,4,5,5] --> 1, 2, 3, 4, 5
[1,2,3,3,4,4,5,5] --> 3, 4, 5

示例 3:

输入: nums = [1,2,3,4,4,5]
输出: false
解释: 无法将 nums 分割成长度至少为 3 的连续递增子序列。

提示:

  • 1<=nums.length<=1041 <= nums.length <= 10^4
  • -1000 <= nums[i] <= 1000
  • nums 按非递减顺序排列

解题思路

根据题意分析: 遍历nums元素时,分别记录1、2、3个以上(含)连续值的子串数量(oneCount,towCount,moreThreeCount),初始化都为0;

  • 统计nums[i]元素值出现的次数标记为curCount; 优先将 curCount 个值 连接到 1,2个连续值的子串上;
  • 若有剩余,连接到3个以上(含)个连续值的子串;
  • 若还有剩余,生成1个连续值的子串;连接后,更新对应的 count 值(迁移更新)。若不足,直接返回false。

代码实现

public boolean isPossible(int[] nums) {
    // 超过3个的连续值数量
    int moreThreeCount = 0;
    // 1个连续数量
    int oneCount = 0;
    // 2个连续数量
    int towCount = 0;

    // 
    int last = 0;
    for (int i = 0; i < nums.length;) {
        int start = i;
        for (; start < nums.length && nums[start] == nums[i]; start++) {

        }
        int curCount = start - i;

        if (i == 0 || nums[i] != last + 1) {
            // 不连续
            if (oneCount > 0 || towCount > 0) {
                return false;
            }
            oneCount = curCount;
            towCount = 0;
            moreThreeCount = 0;
        } else {
            // 连续
            if (curCount < oneCount + towCount) {
                return false;
            }
            // oneCount 临时存储
            int temp = curCount - (moreThreeCount + oneCount + towCount);
            moreThreeCount = towCount + Math.min(moreThreeCount, curCount - (oneCount + towCount));
            towCount = oneCount;
            oneCount = temp < 0 ? 0 : temp;
            //System.out.println(curCount + "---"+ i+"---"+oneCount+", " + towCount +", "+ moreThreeCount);
        }
        last = nums[i];
        i = start;
    }
    return oneCount == 0 && towCount == 0;
}

运行结果

Snipaste_2023-03-01_21-55-40.png

复杂度分析

  • 空间复杂度:O(1)O(1)
  • 时间复杂度:O(n)O(n)

掘金(JUEJIN)  一起分享知识, Keep Learning!