LeetCode第248场周赛(7.4)总结

前言

又是一轮三题,第四题剩了大概三十多分钟做不出来,想的几个方法初步估计时间都过不去,运算次数过多

第一题 1920. 基于排列构建数组

题目把怎么做都说出来了,检查一下问题的规模(简单题也可以不看,最好是看一下防止有坑),直接模拟就完事

class Solution {
    public int[] buildArray(int[] nums) {
        int[] res = new int[nums.length];
        for (int i = 0; i < nums.length; i++) {
            res[i] = nums[nums[i]];
        }
        return res;
    }
}

第二题 1921. 消灭怪物的最大数量

你正在玩一款电子游戏,在游戏中你需要保护城市免受怪物侵袭。给你一个 下标从 0 开始 且长度为 n 的整数数组 dist ,其中 dist[i] 是第 i 个怪物与城市的 初始距离(单位:米)。
怪物以 恒定 的速度走向城市。给你一个长度为 n 的整数数组 speed 表示每个怪物的速度,其中 speed[i] 是第 i 个怪物的速度(单位:米/分)。
怪物从 第 0 分钟 时开始移动。你有一把武器,并可以 选择 在每一分钟的开始时使用,包括第 0 分钟。但是你无法在一分钟的中间使用武器。这种武器威力惊人,一次可以消灭任一还活着的怪物。
一旦任一怪物到达城市,你就输掉了这场游戏。如果某个怪物 恰 在某一分钟开始时到达城市,这会被视为 输掉 游戏,在你可以使用武器之前,游戏就会结束。
返回在你输掉游戏前可以消灭的怪物的 最大 数量。如果你可以在所有怪物到达城市前将它们全部消灭,返回 n 。
提示:
n == dist.length == speed.length
1 <= n <= 105
1 <= dist[i], speed[i] <= 105

思路

题目略长,仔细读完题,最直观的想法就是每分钟都击杀当前最近的怪物,也就是贪心,看一下问题的规模,因为每分钟怪物的位置都会变化,所以需要每分钟更新,估计是会超时的,其实就算不超时,贪心也是有问题的,举个极端例子,最远的怪物如果速度最快,一分钟就能直接入城,那么肯定需要击杀这个怪物。所以最后就是个路程/速度=时间的问题,也就是计算出怪物到达城市的耗时,再每分钟处理当前耗时最短的怪物即可。

class Solution {
    public int eliminateMaximum(int[] dist, int[] speed) {
        int len = dist.length;
        //当前怪物进城需要的时间
        int[] mins = new int[len];
        for (int i = 0; i < len; i++) {
            float f = (float) dist[i] / speed[i];
            mins[i] = (int) Math.ceil(f);
        }
        //按进城费时排序,一个个处理
        Arrays.sort(mins);
        int res = 0;
        for (; res < len; res++) {
            if (res >= mins[res]) {
                return res;
            }
        }
        return res;

    }
}

以上是周赛的时候写的代码,因为考虑到怪物如果1.5分钟能入城,那么就需要以2分钟入城计算,因为每分钟开始时才能使用武器,但实际上并不需要做向上取整再转换为整型,直接用float数组(当前怪物入城耗时)和int(时间)做比较即可

第三题 5802. 统计好数字的数目

我们称一个数字字符串是 好数字 当它满足(下标从 0 开始)偶数 下标处的数字为 偶数 且 奇数 下标处的数字为 质数 (2,3,5 或 7)。
比方说,"2582" 是好数字,因为偶数下标处的数字(2 和 8)是偶数且奇数下标处的数字(5 和 2)为质数。但 "3245" 不是 好数字,因为 3 在偶数下标处但不是偶数。
给你一个整数 n ,请你返回长度为 n 且为好数字的数字字符串 总数 。由于答案可能会很大,请你将它对 109 + 7 取余后返回 。
一个 数字字符串 是每一位都由 0 到 9 组成的字符串,且可能包含前导 0 。
提示:
1 <= n <= 10的15次方

思路

比较容易看出来偶数列的可能为5种(因为包含前导0),奇数列的可能为4种,也就是5454...5 或者是5454...4的结构,实现很容易,难点在于问题的规模太大,10的15次方,直接遍历肯定是不行的,结合以前做过的求幂的题目,可以每次翻倍,用空间记录下重复计算的值(目测这里不这样做也能通过),周赛的时候恰好想到了以前看别人题解使用静态变量提速,所以本次也就尝试用了一下,感觉还可以。

    static int MASK = 1000000007;
    static long[] KEY = new long[100];
    static long[] VALUE = new long[100];
    static int MAX = 0;
    static {
        KEY[0] = 2;
        VALUE[0] = 20;
    }
    public int countGoodNumbers(long n) {
        long count = KEY[MAX];
        long res = VALUE[MAX];
        int max = MAX + 1;
        //计算value,也就是n为2.4.6.8...对应的答案,使用静态变量减少重复计算次数,测试用例很多时,此处可以少计算很多次
        if(KEY[max] < n) {
            while (count < n) {
                res *= res;
                if (res >= MASK) {
                    res %= MASK;
                }
                count *= 2;
                KEY[max] = count;
                VALUE[max++] = res;
            }
            res = 1;
            max--;
            MAX = max;
        }
        //拼接出实际输入n所对应的值,此处可以考虑二分查找优化,周赛时时间太紧直接遍历的
        while (n >= 2) {
            for (int i = max; i >= 0; i--) {
                if (n >= KEY[i]) {
                    n -= KEY[i];
                    max = i - 1;
                    res *= VALUE[i];
                    if (res >= MASK) {
                        res %= MASK;
                    }
                    break;
                }
            }
        }
        //最后n可能剩一个 也就是5454...5的情况,前面都是20的次幂,后面需要额外乘以5
        if (n == 1) {
            res *= 5;
            if (res >= MASK) {
                res %= MASK;
            }
        }
        return (int) res;
    }

试了一下,同样的算法,不使用静态变量耗时1ms,使用之后变成0ms


消耗比.png

快速幂

时间上来说复杂度是和上面算法相同的,代码优雅了不是一个级别,也算是快速幂的模板了,数学上也比较好理解

    public int countGoodNumbers1(long n) {
        int k = 1000000007;
        long a = n >> 1;
        long res = 1;
        long base = 20;
        while(a > 0){
            if ((a & 1) == 1) {
                res = (res * base) % k;
            }
            a >>= 1;
            base = (base * base) % k;
        }
        return (int) ((n & 1) == 1 ? (res * 5) % k : res);
    }

总结

第三题做的太慢了前两题差不多十五分钟内,第三题用了半小时才弄出来,实际上快速幂的题以前做过,没记公式,完全忘了,又用记忆法重新推导了一遍

你可能感兴趣的:(LeetCode第248场周赛(7.4)总结)