leetcode第291场周赛总结复盘


前言

经过将近一年的刷题和总结学习,感觉算法的基础部分算是啃下来了,但是还没有吃透,模拟、滑动窗口、集合的应用,动态规划、dfs…但是还是有很多还没有学习和掌握的,例如:图、并查集、bfs等等。怀揣着激动的心尝试了自己的第一次周赛,结果有些不尽人意,特作此复盘,希望自己和各位一样能不断学习和继续进步叭~


题目与题解

先分享一下自己的题目与题解,有更好的题解方法也可以在评论区分享一起学习!

1.移除指定数字得到最大结果(Easy)

题目链接

题目:

给你一个表示某个正整数的字符串 number 和一个字符 digit 。
从 number 中 恰好 移除 一个 等于 digit 的字符后,找出并返回按 十进制 表示 最大 的结果字符串。生成的测试用例满足 digit 在 number 中出现至少一次。

在这里插入图片描述

思路

其实第一题是简单题,按道理来说应该没那么复杂,所以我一上来就是将遍历字符串,遇到符合条件的digit时就删除这个字符然后将其转换成Integer进行比较

错误代码1
class Solution {
    public String removeDigit(String number, char digit) {
        int result=0;
        int n=number.length();
        for(int i=0;i<n;i++){
            if(number.charAt(i)==digit){
                //如果当前字符与所示字符相同,那么将其移除
                String str=number.substring(0,i)+number.substring(i+1,n);
                int temp=Integer.valueOf(str);
                result=max(result,temp);
            }
        }
        return String.valueOf(result);
    }
    
    public int max(int a,int b){
        return a>b?a:b;
    }
}
运行结果1

在这里插入图片描述
仔细看题之后发现整个字符串可以长达100位,我使用Integer会不会是远远不够了hh,所以我必须转变思路,使用字符串进行比较

于是我转变思路:能不能通过字符串的一些规律来解决此题
对于任意一个字符串str,我发现遇到的第一个匹配字符是相当重要的,例如:

示例1:
str=“3213”,digit=‘3’

去掉第一个3会使结果变成213,去掉第2个3会让结果变成321(优)

示例2:
str=“3413”,digit=‘3’

去掉第1个3会使结果变成413(优),去掉第2个3会让结果变成341

示例3:
str=“3313”,digit=‘3’

去掉第1个3或第2个3都是313,去掉最后一个3会使结果位331(优)

示例4:
str=“44443313”,digit=‘3’

如示例3,前面的数对其没有影响

因此得出结论:如果当前子串的数字为digit,那么需要结合下一位进行判断,如果下一位大于digit,那么就直接删除这个数然后返回结果即可(埋坑)

错误代码2
class Solution {
    public String removeDigit(String number, char digit) {
        int n=number.length();
        String result="";
        int nums=0;
        /****
            第一轮找是否只有一个字符
        **/
        for(int i=0;i<n;i++){
            if(number.charAt(i)==digit){
                nums++;
            }
        }
        if(nums==1){
            for(int i=0;i<n;i++){
                if(number.charAt(i)==digit){
                    result=number.substring(0,i)+number.substring(i+1,n);
                    break;
                }
            }
        }else{
            //至少有两个符合条件的字符
            for(int i=0;i<n;i++){
                if(number.charAt(i)==digit){
                    if(i==n-1){
                        result=number.substring(0,n-1);
                        break;
                    }
                    if(number.charAt(i+1)>number.charAt(i)){
                        result=number.substring(0,i)+number.substring(i+1,n);
                        break;
                    }
                }
            }
        }
        
        return result;
    }
}

运行返回的结果是:“”(空子串)

分析:
为什么返回的是空子串呢,因为到最后一个5时还没有符合条件,所以整个字符串跳过去后都进行操作,也就没有结果返回了,所以我还需要记录这是不是操作的最后一个数

正确代码
class Solution {
    public String removeDigit(String number, char digit) {
        int n=number.length();
        String result="";
        int nums=0;
        /****
            第一轮找是否只有一个字符
        **/
        for(int i=0;i<n;i++){
            if(number.charAt(i)==digit){
                nums++;
            }
        }
        if(nums==1){
            for(int i=0;i<n;i++){
                if(number.charAt(i)==digit){
                    result=number.substring(0,i)+number.substring(i+1,n);
                    break;
                }
            }
        }else{
            //至少有两个符合条件的字符
            for(int i=0;i<n;i++){
                if(number.charAt(i)==digit){
                    nums--;     //表示后面还有几个数
                    if(i==n-1||nums==0){
                        result=number.substring(0,i)+number.substring(i+1,n);
                        break;
                    }
                    if(number.charAt(i+1)>number.charAt(i)){
                        result=number.substring(0,i)+number.substring(i+1,n);
                        break;
                    }
                }
            }
        }
        
        return result;
    }
}

在这里插入图片描述
第一题做成这样实属不应该,罚时了20分钟加上思考了30分钟,也就成为了拖后腿的一题.

2.必须拿起的最小连续卡牌数

题目链接

题目

在这里插入图片描述

思路

这题我一开始是想用哈希表来存储每个数字出现的位置的,然后再遍历哈希表来计算每个key中的value差值最小值,后来一想其实不需要那么复杂,cards[i]在[0,106]之间,使用数组来实现哈希表或许会更加简单,思路清晰后也很快编写出对应的代码:

正确代码
class Solution {
    public int minimumCardPickup(int[] cards) {
        /****
            使用数组来存储对应数和对应位置
        **/
        int n = cards.length;
        int[] idx = new int[1000001];
        for(int i=0;i<idx.length;i++){
            idx[i]=-1;
        }
        int result=1000001;
        for(int i=0;i<n;i++){
            if(idx[cards[i]]!=-1){
                //说明之前这个数之前出现过,那么找出上一个出现该数的位置
                int subIndex=i-idx[cards[i]]+1;
                result=Math.min(result,subIndex);
            }
            idx[cards[i]]=i;
        }
        
        return result==1000001?-1:result;
    }
}

运行结果
在这里插入图片描述

3.含最多k个可整除元素的子数组

题目链接

题目

在这里插入图片描述

思路

其实这题也并不复杂,像是作一个符合条件的全排列,问题就在于我对于Set集合和List集合理解不够深入,导致测试时本题卡了好久,提交本题时已经结束10分钟了,自然分数也就没有拿到,有点可惜吧

上文提到这里可以使用Set实现去重,不断比较是否可以添加进新的元素进List,然后将List放入Set中实现去重,于是第一版的错误代码便应运而生了…

错误代码1
class Solution {
    /****
     全排列问题,使用Set去重会更佳
     ***/
    public int countDistinct(int[] nums, int k, int p) {
        int n = nums.length;
        Set<List<Integer>> set=new HashSet<>();
        for(int i=0;i<n;i++){
            List<Integer> list = new ArrayList<>();
            int temp = k;
            for(int j=i;j<n;j++){
                if(nums[j]%p==0){
                    if(temp==0){
                        break;
                    }
                    temp--;
                }
                list.add(nums[j]);
                set.add(list);
            }
        }

        return set.size();
    }
}

错误结果:

填入示例:
nums={2, 3, 3, 2, 2},k=2,p=2后结果为14,而不是正确结果11,为此我进行调试,调试时发现很多"诡异"之处:

第一次进入内层循环时:set中的list有1个,为{2}
在这里插入图片描述
第二次进入内层循环时:set中的list有两个,且它们都是{2,3}
在这里插入图片描述
由于第一次调试时心情急躁,也就没有认真仔细一步步调试,而是到最后才发现竟然有许多重复的集合,这让我一时间很无解,后来我才发现我操作的都是同一条链表,即对同一引用进行了重复的操作,原来的链表也会随着add操作而继续改变,想清楚这点时,比赛已经结束了,但是我还是提交了代码,结果真就差了亿点…

正确代码
class Solution {
    /****
     全排列问题,使用Set去重会更佳
     ***/
    public int countDistinct(int[] nums, int k, int p) {
        int n = nums.length;
        Set<List<Integer>> set=new HashSet<>();
        for(int i=0;i<n;i++){
            List<Integer> list = new ArrayList<>();
            int temp = k;
            for(int j=i;j<n;j++){
                if(nums[j]%p==0){
                    if(temp==0){
                        break;
                    }
                    temp--;
                }
                list.add(nums[j]);
                //每次都使用新的链表来存取数据
                List<Integer> temps = new ArrayList<>(list);
                set.add(temps);
            }
        }

        return set.size();
    }
}

运行结果:
在这里插入图片描述
由于第4题题目都来不及看了,因此在此就不进行复盘了,有兴趣的同学可以去看一下.

总结

本次周赛难度还是偏低的,但是我也因为第一题而有点慌了阵脚,思维还需要继续锻炼并强化自己的数据结构方面的知识能力!本次打榜全国排名3867,其实还是很有机会能够冲击前2000名的,主要是失误+知识点不牢固,希望能够再接再厉,一起加油~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Astronaut_001

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值