开启我的LeetCode刷题日记:2100. 适合打劫银行的日子

152 阅读2分钟

Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情

编程世界总是离不了算法

最近在看框架源码时,会有很多算法的实现逻辑,有时候会感到吃力

于是决定蹭着假期,加强算法和数据结构相关的知识

那怎么提升呢?

其实我知道算法这东西没有捷径,多写多练才能提升,于是我开启我的LeetCode刷题之旅

第一阶段目标是:200道,每天12

为了不乱,本系列文章目录分为三部分:

  1. 今日题目:xxx
  2. 我的思路
  3. 代码实现

今天题目:2100. 适合打劫银行的日子

你和一群强盗准备打劫银行。给你一个下标从 0 开始的整数数组 security ,其中 security[i] 是第 i 天执勤警卫的数量。日子从 0 开始编号。同时给你一个整数 time 。

如果第 i 天满足以下所有条件,我们称它为一个适合打劫银行的日子:

第 i 天前和后都分别至少有 time 天。 第 i 天前连续 time 天警卫数目都是非递增的。 第 i 天后连续 time 天警卫数目都是非递减的。 更正式的,第 i 天是一个合适打劫银行的日子当且仅当:security[i - time] >= security[i - time + 1] >= ... >= security[i] <= ... <= security[i + time - 1] <= security[i + time].

请你返回一个数组,包含 所有 适合打劫银行的日子(下标从 0 开始)。返回的日子可以 任意 顺序排列。

 

示例 1:

输入:security = [5,3,3,3,5,6,2], time = 2 输出:[2,3] 解释: 第 2 天,我们有 security[0] >= security[1] >= security[2] <= security[3] <= security[4] 。 第 3 天,我们有 security[1] >= security[2] >= security[3] <= security[4] <= security[5] 。 没有其他日子符合这个条件,所以日子 2 和 3 是适合打劫银行的日子。 示例 2:

输入:security = [1,1,1,1,1], time = 0 输出:[0,1,2,3,4] 解释: 因为 time 等于 0 ,所以每一天都是适合打劫银行的日子,所以返回每一天。 示例 3:

输入:security = [1,2,3,4,5,6], time = 2 输出:[] 解释: 没有任何一天的前 2 天警卫数目是非递增的。 所以没有适合打劫银行的日子,返回空数组。 示例 4:

输入:security = [1], time = 5 输出:[] 解释: 没有日子前面和后面有 5 天时间。 所以没有适合打劫银行的日子,返回空数组。  

提示:

1 <= security.length <= 105 0 <= security[i], time <= 105

我的思路

思路: 1.本题使用了动态规划的方法,时间复杂度为O(n)。 由题意,我们要找到对于任一security[i],它的前time天都是递减,它的后time天都是递增,很容易我们想到,当我们使用遍历的方法的时候,当我们计算出security[i]是否满足条件后,security[i + 1]是可以复用计算结果的,而动态规划的本质就在于复用计算结果,避免重复运算,所以我们想到尝试使用动态规划。

2.现在问题在于通过设计出表格来确定是一维动态规划还是二维动态规划,很明显,我们发现我们只需要遍历一遍security数组,找出其中所有的满足条件的下标就可以,所以是一维动态规划。

3.现在的问题来到了,当已知secuirty[i]满足条件,我们如何找到security[i+1]是否满足条件,首先当security[i]满足条件,那么说明对于security[i]左边,满足security[i - time] >= security[i - time + 1] >= ... >= security[i],说明security[i]左边有time天非递增,那么对于security[i + 1] 我们可以使用一个数组left来储存对应结果,left[i]表示security[i]左边的非递增的天数。

如果security[i + 1] <= security[i],那么security[i + 1]左边有left[i] + 1天非递增。 如果security[i + 1] > security[i],那么security[i + 1]左边有0天非递增。 4.当我们需要找右边的时候,可以从security数组的尾开始遍历,这样就是如果security[i + 1]满足条件,那么对于security[i] 我们可以使用一个数组right来储存对应结果,right[i]表示security[i]左边的非递增的天数。

如果security[i] <= security[i + 1],那么security[i]右边有right[i + 1] + 1天非递减。 如果security[i] > security[i + 1],那么security[i]右边有0天非递减。 5.最后我们只需要再进行一次遍历,找出left和right都满足条件的i就可以找出答案了

代码实现

/**
 * @param {number[]} security
 * @param {number} time
 * @return {number[]}
 */
var goodDaysToRobBank = function(security, time) {
    const n = security.length
    const left = new Array(n).fill(0);
    const right = new Array(n).fill(0);
    for(let i = 1;i < n;i++)
    {
        if(security[i] <= security[i - 1])
        {
            left[i] = left[i - 1] + 1;
        }
    }
    for(let i = n - 2;i >= 0;i--)
    {
        if(security[i] <= security[i + 1])
        {
            right[i] = right[i + 1] + 1;
        }
    }
    const res = [];
    for(let i = time;i < n - time;i++)
    {
        if(left[i] >= time && right[i] >= time)
        {
            res.push(i);
        }
    }
    return res;
};


总结

实现方式其实有很多,这里仅供参考~

由于刚开始刷题,也不知道从哪里刷好,如果前辈们有好的建议,希望不吝赐教,感谢🌹