【LeetCode笔记 - 每日一题】2100. 适合打劫银行的日子(Java、数组、前缀和)

0306 潮汕旅游回来啦,吃胖了,想学潮汕话(闽南语系)。恢复写题~

数组、前缀和

题目

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

  • 第 i 天前和后都分别至少有 time 天。
  • 第 i 天前连续 time 天警卫数目都是非递增的。
  • 第 i 天后连续 time 天警卫数目都是非递减的。

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

示例

输入: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 是适合打劫银行的日子。

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

思路 & 代码

  1. 简单说就是求长度合适的V字子数组。线性遍历,空间换时间,对每一个位置,看前方符合非递增的最长子数组长度,用一个数组dec记录;看后方非递减最长,用inc记录。最后看哪些位置的前后长度都满足>time
class Solution {
    public List<Integer> goodDaysToRobBank(int[] se, int ti) {
        int n = se.length;
        List<Integer> res = new ArrayList<>();
        if (n < ti * 2 + 1) return res; // 长度不符合,提前结束
        int[] dec = new int[n], inc = new int[n];
        int cnt = 0; // 统计截止当前位置的连续情况
        for (int i = 1; i < n; i++) { // 前方
            if (se[i - 1] >= se[i]) ++cnt; // 满足就长度+1
            else cnt = 0; // 不满足就重新开始统计
            dec[i] = cnt;
        }
        cnt = 0; 
        for (int i = n - 2; i >= 0; i--) { // 后方
            if (se[i + 1] >= se[i]) ++cnt;
            else cnt = 0;
            inc[i] = cnt;
        }
        for (int i = 0; i < n; i++) { // 判断答案候选
            if (dec[i] >= ti && inc[i] >= ti) res.add(i);
        }
        return res;
    }
}

执行用时:5 ms, 在所有 Java 提交中击败了98.22%的用户

内存消耗:59.4 MB, 在所有 Java 提交中击败了11.15%的用户

通过测试用例:144 / 144

** 草稿的几个bug(所以说调试功能还是很有用的)**

  • 答案要的是下标i
  • 非递增/递减,注意不是严格增减。所以预处理数组、判断的时候是>=缺了等号就gg。
  1. 大佬的解法

by 宫水三叶(每次点赞都排第一啊),说实话预处理我有点没懂。可能写完周赛脑子不够使了😂

class Solution {
    public List<Integer> goodDaysToRobBank(int[] security, int time) {
        int n = security.length;
        int[] g = new int[n];
        for (int i = 1; i < n; i++) {
            if (security[i] == security[i - 1]) continue;
            g[i] = security[i] > security[i - 1] ? 1 : -1;
        }
        int[] a = new int[n + 1], b = new int[n + 1];
        for (int i = 1; i <= n; i++) a[i] = a[i - 1] + (g[i - 1] == 1 ? 1 : 0);
        for (int i = 1; i <= n; i++) b[i] = b[i - 1] + (g[i - 1] == -1 ? 1 : 0);
        List<Integer> ans = new ArrayList<>();
        for (int i = time; i < n - time; i++) {
            int c1 = a[i + 1] - a[i + 1 - time], c2 = b[i + 1 + time] - b[i + 1];
            if (c1 == 0 && c2 == 0) ans.add(i);
        }
        return ans;
    }
}

作者:AC_OIer
链接:https://leetcode-cn.com/problems/find-good-days-to-rob-the-bank/solution/gong-shui-san-xie-qian-zhui-he-yun-yong-gf604/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值