算法初探LeetCode-删掉一个元素以后全为 1 的最长子数组

64 阅读2分钟

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

LeetCode1493:删掉一个元素以后全为 1 的最长子数组

给你一个二进制数组 nums ,你需要从中删掉一个元素。

请你在删掉元素的结果数组中,返回最长的且只包含 1 的非空子数组的长度。

如果不存在这样的子数组,请返回 0 。 提示 1:

输入: nums = [1,1,0,1]
输出: 3
解释: 删掉位置 2 的数后,[1,1,1] 包含 3 个 1 。

示例 2:

输入: nums = [0,1,1,1,0,1,1,0,1]
输出: 5
解释: 删掉位置 4 的数字后,[0,1,1,1,1,1,0,1] 的最长全 1 子数组为 [1,1,1,1,1]

示例 3:

输入: nums = [1,1,1]
输出: 2
解释: 你必须要删除一个元素。

提示:

  • 1<=nums.length<=105 1 <= nums.length <= 10^5
  • nums[i] 要么是 0 要么是 1 。

思路分析

先计算出0的个数,然后new一个二位数组arr arr[i][0]表示第i个零左边连1有多少个,arr[i][1]代表第i个零右边连续1有多少个; 然后再遍历这个数组,将其左右连续1相加,取最小即可

这里有个小技巧:在计算0的个数的时候0处的值为新数组arr第一个下标的负数

考虑最长子数组中包含一个值为0的元素,不能包含两个;可以以滑动窗口中值为0的个数作为判断条件控制窗口滑动

算法代码

public int longestSubarray(int[] nums) {
    int zeroNum = 0;
    int len = nums.length;
    for (int i = 0; i < len; i++) {
        if (nums[i] == 0) {
            zeroNum++;
            nums[i] = -zeroNum + 1;
        }
    }
    if (zeroNum == 0) return len - 1;
    int[][] arr = new int[zeroNum][2];
    int left = 0, right = 0;
    for (int j = 0; j < len; j++) {
        int cur = nums[j];
        if (cur <= 0) {
            arr[-cur][0] = left;
            left = 0;
        }
        if (cur == 1) left++;
    }
    for (int k = len - 1; k >= 0; k--) {
        int cur = nums[k];
        if (cur <= 0) {
            arr[-cur][1] = right;
            right = 0;
        }
        if (cur == 1) right++;
    }
    int ans = 0;
    for (int m = 0; m < zeroNum; m++) {
        ans = Math.max((arr[m][0] + arr[m][1]), ans);
    }
    return ans;
}

结果详情

Snipaste_2023-02-13_23-02-39.png

算法复杂度

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

掘金(JUEJIN)一起进步,一起成长!