周赛313赛后做题分析及总结

212 阅读1分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第4天,点击查看活动详情

入坑力扣周赛以来,从一开始的0题选手到现在慢慢已经能做出2题左右了,能很明显地感觉到最近几场的周赛难度有所降低(而且从数据上看,之前做出两题能排到2000多,最近只能到4000多),打比赛就是这样,你追我赶,逆水行舟,不进则退。目前我做三四题还处于赛时一脸懵,赛后马后炮的状态,希望通过不断总结与反思,能慢慢跨上新台阶。 ————写在最前面

Q1:枚举因子

送分题:

class Solution {
    public int commonFactors(int a, int b) {
        int cnt=0;
        int min=(a>b)?b:a;
        for(int i=1;i<=min;i++){
            if(a%i==0&&b%i==0) cnt++;
        }
        return cnt;
    }
}

Q2:沙漏的最大总和

我的方法有点笨,没有技巧,只剩感情。

对于矩阵中的每个元素,如果它往下往右扩展3个单位的范围没有越界,就去计算该范围除了腰间两个数以外的总数和。

class Solution {
    public int maxSum(int[][] grid) {
        int m=grid.length,n=grid[0].length;
        int res=0;
        for(int i=0;i<m;i++){
            for(int j=0;j<n;j++){
                if(i+3<=m&&j+3<=n){
                    res=Math.max(res,getSum(grid,i,j));
                }
            }
        }
        return res;
    }
    
    public int getSum(int [][] grid,int i,int j){
        int sum=0;
        int a=0;
        while(a<3){
            int b=0,tmp=j;
            while(b<3){
                sum+=(a==1&&b!=1)?0:grid[i][tmp];
                b++;
                tmp++;
            }
            a++;
            i++;
        }
        return sum;
    }
}

Q3:最小XOR

这个我当时想到了是从高位到低位补1,如果1还没用完,就反过来从低位到高位继续补。不过比赛中途代码差了点意思,用了转字符串之类的方法。赛后一看 @灵茶山艾府 大佬的解法,醍醐灌顶,原来可以直接原地位运算。

class Solution {
    public int minimizeXor(int num1, int num2) {
        int bitcnta=Integer.bitCount(num1);
        int bitcntb=Integer.bitCount(num2);
        int bitlena=0;
        int tmp=num1;
        while(tmp>0){
            tmp/=2;
            bitlena++;
        }
        int x=0;
        if(bitcntb>=bitlena) return (1<<bitcntb)-1;
        //总体思路:从高位往低位用1,用不完的再从低位往高位补
        while(bitcntb<bitcnta){
            num1&=num1-1;
            bitcntb+=1;
        }
        x=~num1;
        while(bitcnta<bitcntb){
            num1|=x&-x;
            x&=x-1;
            bitcntb-=1;
        }
        return num1;
    }
}

Q4:对字母串可执行的最大删除数

据力扣大佬们说这是经典dp问题。(虽然我当时是没有看出来的,但是看了大佬们的解法觉得很有道理。)

lcp数组和dp数组都是逆着用的,他们似乎管这叫“记忆化搜索”(不知道有没有记错)

lcp数组记录的是字符串的最长公共前缀(longest common prefix),dp记录的是删除后缀后所需要的最大操作数。

如果当前两个字符相等,即lcp前后两个状态相差1;

第二个双for循环中,if的作用是判断两个子串是否相等,是,就取最大值。

class Solution {
    public int deleteString(String s) {
        int n=s.length();
        int [][] lcp=new int [n+1][n+1];
        int [] dp=new int [n];
        for(int i=n-1;i>=0;i--){
            for(int j=n-1;j>=0;j--){
                if(s.charAt(i)==s.charAt(j)){
                    lcp[i][j]=lcp[i+1][j+1]+1;
                }
            }
        }

        for(int i=n-1;i>=0;i--){
            for(int j=1;i+j*2<=n;j++){
                if(lcp[i][i+j]>=j){
                    dp[i]=Math.max(dp[i],dp[i+j]);
                }
            }
            dp[i]++;
        }
        return dp[0];
    }
}