LeetCode342. 4的幂 / 第243场周赛

Posted Zephyr丶J

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LeetCode342. 4的幂 / 第243场周赛相关的知识,希望对你有一定的参考价值。

342. 4的幂

2021.5.31 每日一题,很开心这个月又收货徽章了!

题目描述

给定一个整数,写一个函数来判断它是否是 4 的幂次方。如果是,返回 true ;否则,返回 false 。

整数 n 是 4 的幂次方需满足:存在整数 x 使得 n == 4x


示例 1:

输入:n = 16
输出:true
示例 2:

输入:n = 5
输出:false
示例 3:

输入:n = 1
输出:true

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/power-of-four
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

也想用简单一行的方法,但是没太想出来哈哈,就只能找二进制位的1在哪个位置了

class Solution {
    public boolean isPowerOfFour(int n) {
        //4的幂,就是统计这个1在第几位,如果是偶数位,就是4的幂
        if(n <= 0)
            return false;
        int count = 1;
        while((n & 1) != 1){
            n >>= 1;
            count++;
        }
        count++;
        return n == 1 && count % 2 == 0;
    }
}

官解的写法,构造一个奇数位都是1的整数,然后与n相与,如果是0,就表示是4的幂(是2的幂的前提下)
或者对3取余数,4的幂对3取余是1,如果是2的幂对3取余是2

class Solution {
    public boolean isPowerOfFour(int n) {
        return n > 0 && (n & (n - 1)) == 0 && (n & 0xaaaaaaaa) == 0;
        //return n > 0 && (n & (n - 1)) == 0 && n % 3 == 1;
    }
}

第243场周赛

这场咋说呢,也是前两道秒过吧,第三道能做但卡,第四道基本没咋看,和周六晚上的双周赛基本一个节奏,下次目标还是三道题,不过排名进步了哈哈

1880. 检查某单词是否等于两单词之和

题目描述

字母的 字母值 取决于字母在字母表中的位置,从 0 开始 计数。即,'a' -> 0、'b' -> 1、'c' -> 2,以此类推。

对某个由小写字母组成的字符串 s 而言,其 数值 就等于将 s 中每个字母的 字母值 按顺序 连接 并 转换 成对应整数。

例如,s = "acb" ,依次连接每个字母的字母值可以得到 "021" ,转换为整数得到 21 。
给你三个字符串 firstWord、secondWord 和 targetWord ,每个字符串都由从 'a' 到 'j' (含 'a' 和 'j' )的小写英文字母组成。

如果 firstWord 和 secondWord 的 数值之和 等于 targetWord 的数值,返回 true ;否则,返回 false 。


示例 1:

输入:firstWord = "acb", secondWord = "cba", targetWord = "cdb"
输出:true
解释:
firstWord 的数值为 "acb" -> "021" -> 21
secondWord 的数值为 "cba" -> "210" -> 210
targetWord 的数值为 "cdb" -> "231" -> 231
由于 21 + 210 == 231 ,返回 true
示例 2:

输入:firstWord = "aaa", secondWord = "a", targetWord = "aab"
输出:false
解释:
firstWord 的数值为 "aaa" -> "000" -> 0
secondWord 的数值为 "a" -> "0" -> 0
targetWord 的数值为 "aab" -> "001" -> 1
由于 0 + 0 != 1 ,返回 false
示例 3:

输入:firstWord = "aaa", secondWord = "a", targetWord = "aaaa"
输出:true
解释:
firstWord 的数值为 "aaa" -> "000" -> 0
secondWord 的数值为 "a" -> "0" -> 0
targetWord 的数值为 "aaaa" -> "0000" -> 0
由于 0 + 0 == 0 ,返回 true

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/check-if-word-equals-summation-of-two-words
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

没啥好说的,变成数字,判断加法就行了

class Solution {
    public boolean isSumEqual(String firstWord, String secondWord, String targetWord) {
        int num1 = 0;
        for(int i = 0; i < firstWord.length(); i++){
            num1 = num1 * 10 + firstWord.charAt(i) - 'a';
        }
        int num2 = 0;
        for(int i = 0; i < secondWord.length(); i++){
            num2 = num2 * 10 + secondWord.charAt(i) - 'a';
        }
        int num3 = 0;
        for(int i = 0; i < targetWord.length(); i++){
            num3 = num3 * 10 + targetWord.charAt(i) - 'a';
        }
        return num1 + num2 == num3;
    }
}

1881. 插入后的最大值

题目描述

给你一个非常大的整数 n 和一个整数数字 x ,大整数 n 用一个字符串表示。n 中每一位数字和数字 x 都处于闭区间 [1, 9] 中,且 n 可能表示一个 负数 。

你打算通过在 n 的十进制表示的任意位置插入 x 来 最大化 n 的 数值 ​​​​​​。但 不能 在负号的左边插入 x 。

例如,如果 n = 73 且 x = 6 ,那么最佳方案是将 6 插入 7 和 3 之间,使 n = 763 。
如果 n = -55 且 x = 2 ,那么最佳方案是将 2 插在第一个 5 之前,使 n = -255 。
返回插入操作后,用字符串表示的 n 的最大值。


示例 1:

输入:n = "99", x = 9
输出:"999"
解释:不管在哪里插入 9 ,结果都是相同的。
示例 2:

输入:n = "-13", x = 2
输出:"-123"
解释:向 n 中插入 x 可以得到 -213、-123 或者 -132 ,三者中最大的是 -123 。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/maximum-value-after-insertion
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

我当时还在想有0要怎么处理一下,结果一看没有0,那不用多说了

class Solution {
    public String maxValue(String n, int x) {
        //如果n是正数,就从左到右,如果找到大于的第一个数左边插入
        //如果是负数,找到小于的第一个数左边插入
        int l = n.length();
        boolean flag = n.charAt(0) == '-' ? false : true;
        int index = 0;
        if(flag){
            while(index < l){
                char c = n.charAt(index);
                if(x > c - '0')
                    break;
                index++;
            }
        }else{
            index = 1;
            while(index < l){
                char c = n.charAt(index);
                if(x < c - '0')
                    break;
                index++;
            }
        }
        char[] s = new char[l + 1];
        for(int i = 0; i <= l; i++){
            if(i < index)
                s[i] = n.charAt(i);
            else if(i == index)
                s[i] = (char)(x + 48);
            else
                s[i] = n.charAt(i - 1);
        }
        return new String(s);
        
    }   
}

1882. 使用服务器处理任务

题目描述

给你两个 下标从 0 开始 的整数数组 servers 和 tasks ,长度分别为 n​​​​​​ 和 m​​​​​​ 。servers[i] 是第 i​​​​​​​​​​ 台服务器的 权重 ,而 tasks[j] 是处理第 j​​​​​​ 项任务 所需要的时间(单位:秒)。

你正在运行一个仿真系统,在处理完所有任务后,该系统将会关闭。每台服务器只能同时处理一项任务。第 0 项任务在第 0 秒可以开始处理,相应地,第 j 项任务在第 j 秒可以开始处理。处理第 j 项任务时,你需要为它分配一台 权重最小 的空闲服务器。如果存在多台相同权重的空闲服务器,请选择 下标最小 的服务器。如果一台空闲服务器在第 t 秒分配到第 j 项任务,那么在 t + tasks[j] 时它将恢复空闲状态。

如果没有空闲服务器,则必须等待,直到出现一台空闲服务器,并 尽可能早 地处理剩余任务。 如果有多项任务等待分配,则按照 下标递增 的顺序完成分配。

如果同一时刻存在多台空闲服务器,可以同时将多项任务分别分配给它们。

构建长度为 m 的答案数组 ans ,其中 ans[j] 是第 j 项任务分配的服务器的下标。

返回答案数组 ans​​​​ 。


示例 1:

输入:servers = [3,3,2], tasks = [1,2,3,2,1,2]
输出:[2,2,0,2,1,2]
解释:事件按时间顺序如下:
- 0 秒时,第 0 项任务加入到任务队列,使用第 2 台服务器处理到 1 秒。
- 1 秒时,第 2 台服务器空闲,第 1 项任务加入到任务队列,使用第 2 台服务器处理到 3 秒。
- 2 秒时,第 2 项任务加入到任务队列,使用第 0 台服务器处理到 5 秒。
- 3 秒时,第 2 台服务器空闲,第 3 项任务加入到任务队列,使用第 2 台服务器处理到 5 秒。
- 4 秒时,第 4 项任务加入到任务队列,使用第 1 台服务器处理到 5 秒。
- 5 秒时,所有服务器都空闲,第 5 项任务加入到任务队列,使用第 2 台服务器处理到 7 秒。
示例 2:

输入:servers = [5,1,4,3,2], tasks = [2,1,2,4,5,2,1]
输出:[1,4,1,4,1,3,2]
解释:事件按时间顺序如下:
- 0 秒时,第 0 项任务加入到任务队列,使用第 1 台服务器处理到 2 秒。
- 1 秒时,第 1 项任务加入到任务队列,使用第 4 台服务器处理到 2 秒。
- 2 秒时,第 1 台和第 4 台服务器空闲,第 2 项任务加入到任务队列,使用第 1 台服务器处理到 4 秒。
- 3 秒时,第 3 项任务加入到任务队列,使用第 4 台服务器处理到 7 秒。
- 4 秒时,第 1 台服务器空闲,第 4 项任务加入到任务队列,使用第 1 台服务器处理到 9 秒。
- 5 秒时,第 5 项任务加入到任务队列,使用第 3 台服务器处理到 7 秒。
- 6 秒时,第 6 项任务加入到任务队列,使用第 2 台服务器处理到 7 秒。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/process-tasks-using-servers
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

每次看到这种一长串的题,感觉就是模拟了
然后我想的是把服务器放在优先队列中,按照权重和在servers数组中的位置排序;另外用一个哈希表存储<时间,服务器>的键值对,表示当前时间,哪几个服务器完成了工作
然后遍历时间,如果当前时间有服务器完成工作了,就放入优先队列中;如果当前有工作要完成,就去看优先队列中有没有服务器,如果有就安排到map集合中。

就这样,写了下面的代码,示例过了,但是提交超时了,但是不是数组很大的时候超时,而是不到十个数就超时了,那说明代码有问题,下面是当时写的代码:

class Solution {
    public int[] assignTasks(int[] servers, int[] tasks) {
        //模拟一下吧
        //优先队列,放入服务器,按权重和下标排序
        //然后遍历时间,如果可以分配服务器,就将服务器弹出,同时记录返回的时间,存入一个哈希表中
        PriorityQueue<int[]> pq = new PriorityQueue<>(new Comparator<int[]>(){
            public int compare(int[] a, int[] b){
                return a[0] == b[0] ? a[1] - b[1] : a[0] - b[0];
            }
        });
        int m = servers.length;
        for(int i = 0; i < m; i++){
            pq.offer(new int[]{servers[i], i});
        }
        Map<Integer, List<Integer>> map = new HashMap<>();
        int n = tasks.length;
        int[] res = new int[n];
        int index = 0;
        for(int i = 0; i < n; i++){
            //当前时间,是否有工作完成,有工作完成,把服务器空闲出来
            if(map.containsKey(i)){
                List<Integer> ser = map.get(i);
                map.remove(i);
                for(Integer s : ser){
                    pq.offer(new int[]{servers[s], s});
                }
            }
            while(index <= i){
                if(!pq.isEmpty()){
                    res[index] = pq.peek()[1];
                    if(map.containsKey(i + tasks[index])){
                        List<Integer> list = map.get(i + tasks[index]);
                        list.add(pq.poll()[1]);
                        map.put(i + tasks[index], list);
                    }else{
                        List<Integer> list = new LinkedList<>();
                        list.add(pq.poll()[1]);
                        map.put(i + tasks[index], list);
                    }
                    index++;
                }
            }
            if(index == n)
                break;
        }
        return res;
    }
}

应该是while那部分有问题,改一下看看行不行,简单改了一下,败给了超时,不过也在意料之中,因为时间我是一个一个加的。其实可以改成按tasks中一个个任务来,因为任务的处理是从左到右的,这里就不改了,题解思路也和我的思路差不多
这是我第一次改后的

class Solution {
    public int[] assignTasks(int[] servers, int[] tasks) {
        //模拟一下吧
        //优先队列,放入服务器,按权重和下标排序
        //然后遍历时间,如果可以分配服务器,就将服务器弹出,同时记录返回的时间,存入一个哈希表中
        PriorityQueue<int[]> pq = new PriorityQueue<>(new Comparator<int[]>(){
            public int compare(int[] a, int[] b){
                return a[0] == b[0] ? a[1] - b[1] : a[0] - b[0];
            }
        });
        int m = servers.length;
        for(int i = 0; i < m; i++){
            pq.offer(new int[]{servers[i], i});
        }
        Map<Long, List<Integer>> map = new HashMap<>();
        int n = tasks.length;
        int[] res = new int[n];
        int index = 0;
        //tasks长度最大为200000,m,n的值最大为200000,所以时间最多400000
        //不对,应该是乘
        for(long i = 0; i < 40000000001l; i++){
            //当前时间,是否有工作完成,有工作完成,把服务器空闲出来
            if(map.containsKey(i)){
                List<Integer> ser = map.get(i);
                map.remove(i);
                for(Integer s : ser){
                    pq.offer(new int[]{servers[s], s});
                }
            }
            //如果当前任务的开工时间小于i,表示可以开工
            while(index <= i){
                //如果有服务器空闲
                if(!pq.isEmpty()){
                    //取出第一个服务器的编号
                    res[index] = pq.peek()[1];
                    //如果哈希表中,存在这个时间点,就把这个服务器插入list集合中
                    if(map.containsKey(i + tasks[index])){
                        List<Integer> list = map.get(i + tasks[index]);
                        list.add(pq.poll()[1]);
                        map.put(i + tasks[index], list);
                    //如果没有这个编号,创建这个集合
                    }else{
                        List<Integer> list = new LinkedList<>();
                        list.add(pq.poll()[1]);
                        map.put(i + tasks[index], list);
                    }
                    index++;
                    if(index == n)
                        break;
                //如果没有,就直接跳出                        
                }else{
                    break;
                }
            }
            if(index == n)
                break;
        }
        return res;
    }
}

然后我看题解发现,只要将当服务器都被占用时,时间直接调成下一个服务器空闲的时间,就可以AC了,然后我就把原来的HashMap改成TreeMap,这样可以使服务器时间排序,然后每次服务器都被占用时,时间就可以跳成map.firstKey(),不过这个方法我还是第一次用
然后直接双百了哈哈

class Solution {
    public int[] assignTasks(int[] servers, int[] tasks) {
        //模拟一下吧
        //优先队列,放入服务器,按权重和下标排序
        //然后遍历时间,如果可以分配服务器,就将服务器弹出,同时记录返回的时间,存入一个哈希表中
        PriorityQueue<int[]> pq = new PriorityQueue<>(new Comparator<int[]>(){
            public int compare(int[] a, int[] b){
                return a[0] == b[0] ? a[1] - b[1] : a[0] - b[0];
            }
        });
        int m = servers.length;
        for(int i = 0; i < m; i++){
            pq.offer(new int[]{servers[i], i});
        }
        TreeMap<Long, List<Integer>> map = new TreeMap<>();
        int n = tasks.length;
        int[] res = new int[n]以上是关于LeetCode342. 4的幂 / 第243场周赛的主要内容,如果未能解决你的问题,请参考以下文章

LeetCode342. 4的幂(C++)

leetcode刷题笔记342 4的幂

[LeetCode] 342. 4的幂

leetcode342合理运用位操作判断4的幂

LeetCode 342. 4的幂

LeetCode第243场周赛第三题——5774. 使用服务器处理任务(优先队列)