[杨小白]_leetcode_力扣第 312 场周赛-第三题

178 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第9天,点击查看活动详情

前言

小白算法比较菜,希望能激励我每日更新,从leetcode第一题开始,2022年目标300题,记录从0到1的全过程!!

力扣第 312 场周赛

力扣第 312 场周赛-力扣

a了三题,2000以内,小上10几分。第三题有点离谱,给的例子太基础了,修改了代码之后根本试不出来对不对,错八次可真是,,,,不罚时的话能到1150名呢(当然只能想想)

image.png

这个第三题可得好好说道说道!!!

2420. 找到所有好下标

给你一个大小为 n 下标从 0 开始的整数数组 nums 和一个正整数 k 。

对于 k <= i < n - k 之间的一个下标 i ,如果它满足以下条件,我们就称它为一个 好 下标:

下标 i 之前 的 k 个元素是 非递增的 。

下标 i 之后 的 k 个元素是 非递减的 。

按 升序 返回所有好下标。

示例 1

输入:nums = [2,1,1,1,3,4,1], k = 2

输出:[2,3]

解释:数组中有两个好下标:

  • 下标 2 。子数组 [2,1] 是非递增的,子数组 [1,3] 是非递减的。

  • 下标 3 。子数组 [1,1] 是非递增的,子数组 [3,4] 是非递减的。

  • 注意,下标 4 不是好下标,因为 [4,1] 不是非递减的。

示例 2

  • 输入: nums = [2,1,1,2], k = 2
  • 输出: []
  • 解释: 数组中没有好下标。

提示

  • n == nums.length
  • 3 <= n <= 105
  • 1 <= nums[i] <= 106
  • 1 <= k <= n / 2

解析1

开始并没想到什么好的思路,然后还把题意理解错了几次。

注意

1.要判断的是i前面的k个和后面的k个,不包括i

2.非递增和非递减要理解好!!!

先说暴力吧,暴力确实是简单,结果过不了,如代码1

代码1

暴力很简单,但是作为第三题,能让你用暴力就做出来!?别想了,没门。

class Solution {
    public List<Integer> goodIndices(int[] nums, int k) {
        int left = k;
        int right = nums.length - k - 1;
        if (right < left) return new ArrayList<>();
        List<Integer> res = new ArrayList<>();
        while (left <= right) {
            if (fun(nums, left, k)) {
                res.add(left);
            }
            left++;
        }
        return res;
    }

    public boolean fun(int[] nums, int index, int k) {
        for (int i = 1; i < k; i++) {
            if (!(nums[index + i + 1] >= nums[index + i])) {
                return false;
            }
            if (!(nums[index - i - 1] >= nums[index - i])) {
                return false;
            }
        }
        return true;
    }
}

image.png

解析2

那就暴力剪枝,还是从前往后遍历,如果是在i之前的有个元素发现了异常,那么下次就直接跳到这个异常的元素之后。

直接这么说大家可能不明白,那么看图。

image.png

如图,如果在查找i时,发现i-2(这里用x代表他的序号)不符合条件,那么就不需要判断i+1了,直接跳到x+k+1就好。

同理,尾部也可以剪枝

image.png

在判断i是否满足条件时,发现i+2(这里用x代替序号)不符合条件,那么就不需要判断i+1了,直接令i=x就可以了

代码2

果然,剪枝之后就过了。

class Solution {
    int num;

    public List<Integer> goodIndices(int[] nums, int k) {
        List<Integer> res = new ArrayList<>();
        if (k==1) {
            for (int i = 1; i < nums.length - 1; i++) {
                res.add(i);
            }
            return res;
        }
        int left = k;
        int right = nums.length - k - 1;
        if (right < left) return res;
        while (left <= right) {
            boolean fun = fun(nums, left, k);
            if (fun) {
                res.add(left);
                while (left <= right && fun && left + k + 1 < nums.length - 1) {
                    fun = nums[left - 1] >= nums[left] && nums[left + k] <= nums[left + k + 1];
                    left++;
                    if (fun) {
                        res.add(left);
                    }
                }
                left++;
            } else {
                if (num < left) {
                    left = num + k + 1;
                } else {
                    left = num - 1;
                }
            }

        }
        return res;
    }

    public boolean fun(int[] nums, int index, int k) {
        for (int i = 1; i < k; i++) {
            if (!(nums[index + i + 1] >= nums[index + i])) {
                num = index + i + 1;
                return false;
            }
            if (!(nums[index - i - 1] >= nums[index - i])) {
                num = index - i - 1;
                return false;
            }
        }
        return true;
    }
}

耗时也还ok

image.png

解析3

之后看别人的题解,有一个更简便的方法,能想到这确实真的很牛。

用两个数组,分别记录序号i后面非递减的元素个数,记录了i前面非递增的元素个数。

比如

image.png

遍历这两个数组,判断rise[i-1]>=k && decline[i+1]>=k就可以了

代码2

思路又简单又快!!大佬还是强。

class Solution {
    public List<Integer> goodIndices(int[] nums, int k) {
        int[] rise = new int[nums.length];
        int[] decline = new int[nums.length];
        int index = 1;
        rise[0] = 1;
        for (int i = 1; i < rise.length; i++) {
            if (nums[i] <= nums[i-1]) {
                index++;
            }else {
                index = 1;
            }
            rise[i] = index;
        }
        index = 1;
        decline[decline.length - 1] = 1;
        for (int i = decline.length - 2; i >= 0; i--) {
            if (nums[i] <= nums[i+1]) {
                index++;
            } else {
                index = 1;
            }
            decline[i] = index;
        }
        ArrayList<Integer> res = new ArrayList<>();
        for (int i = k; i < nums.length - k; i++) {
            if (rise[i-1]>=k && decline[i+1]>=k) {
                res.add(i);
            }
        }
        return res;
    }
}

image.png

第一、二题连接如下

[杨小白]_leetcode_力扣第 312 场周赛-第一、二题

第四题连接如下-2430. 对字母串可执行的最大删除数

[杨小白]_leetcode_力扣第 312 场周赛-第四题

3.结束

前两题都不难,基本200题量的同学就可以做出来了,第三题的话,最后的方法确实很巧妙,还是得多见多写。第四题还是无从下手,gogogo,刷题刷题,每天一道,三年1000道!!!!