Leetcode - 135双周赛

目录

一,3222. 求出硬币游戏的赢家

二,3223. 操作后字符串的最短长度

三,3224. 使差值相等的最少数组改动次数

四,3225. 网格图操作后的最大分数


一,3222. 求出硬币游戏的赢家

本题就是一道模拟题,每个人每次只能拿走1枚价值为75的硬币和4枚价值为10的硬币,代码如下:

class Solution {
    public String losingPlayer(int x, int y) {
        int t = -1;
        while(x >= 1 && y >= 4){
            x -= 1;
            y -= 4;
            t *= -1;
        }
        return t==-1?"Bob":"Alice";
    }
}

//进阶版本
class Solution {
    public String losingPlayer(int x, int y) {
        int min = Math.min(x, y/4);
        return min%2==0?"Bob":"Alice";
    }
}

二,3223. 操作后字符串的最短长度

本题求字符串s的最短长度,我们可以先统计每个字符出现的次数,然后暴力,计算出每一个字符最终剩下的次数。题目中所说的删除,实际上是说,如果一个字符出现次数 >= 3,那么可以将其减去2,直到该字符出现次数 < 3。

代码如下:

class Solution {
    public int minimumLength(String s) {
        int[] cnt = new int[26];
        for(char c : s.toCharArray()){
            cnt[c-'a']++;
        }
        int ans = 0;
        for(int x : cnt){
            while(x >= 3){
                x -= 2;
            }
            ans += x;
        }
        return ans;
    }
}

//简化循环版本
class Solution {
    public int minimumLength(String s) {
        int[] cnt = new int[26];
        for(char c : s.toCharArray()){
            cnt[c-'a']++;
        }
        int ans = 0;
        for(int x : cnt){
            if(x > 0)
                ans += x%2==0?2:1;
        }
        return ans;
    }
}

三,3224. 使差值相等的最少数组改动次数

本题如果使用暴力的话,我们可以枚举X的值,再求出将每个差值变成X所需要的最小操作次数,需要知道对于每对(nums[i],nums[n-i-1]),它们什么时候需要操作0次,1次,2次。分情况讨论,(令 p = nums[i],q = nums[n-i-1] 且 p < q):

  • q - p = X,操作 0 次
  • q - p > X,操作 1 次
  • q - p < X && max(q,k-p) >= X,操作 1 次
  • q - p < X && max(q,k-p) < X,操作 2 次

注:max(q,k-p)表示如果只修改1次,那么X的值只能在[0,max(q,k-p)],否则必须要修改2次

为了简化时间复杂度,我们可以进行预处理,使得在枚举X时可以直接得出对于所有(p,q)的差值变成X需要操作的次数。这里有两种做法:

  • 可以使用两个数组,分别统计不需要操作的对数,以及需要操作两次的对数。枚举每一对(p,q),cnt1[q-p]+=1,即如果X=q-p,那么这对数不需要操作;cnt2[max(q,k-q)]+=1,即对于(p,q)如果只能操作1次,那么X最多只能到max(q,k-q),只要X>max(q,k-q),那么这对数就必须要操作两次。得到上述两个数组后,枚举X,最终所需要的操作数就是 n/2 - cnt1[X] + (cnt2[0] + ... + cnt2[X-1])
class Solution {
    public int minChanges(int[] nums, int k) {
        int n = nums.length;
        int[] cnt1 = new int[k+1];
        int[] cnt2 = new int[k+1];
        for(int i=0; i<n/2; i++){
            int x = nums[i], y = nums[n-i-1];
            int mn = Math.min(x, y);
            int mx = Math.max(x, y);
            cnt1[mx-mn] += 1;
            cnt2[Math.max(mx, k-mn)] += 1;
        }   
        int ans = n, pre = 0;
        for(int x=0; x<=k; x++){
            //cnt1[x]:表示刚好等于x,不用修改
            //n/2-cnt1[x]:表示至少需要修改一次的(p,q)数量
            //pre:表示需要修改两次的(p,q)数量
            ans = Math.min(ans, n/2-cnt1[x]+pre);
            pre += cnt2[x];
        }
        return ans;
    }
}
  • 差分数组,简单来说差分数组就是使用简单的操作来实现一段区域内数字的同增或同减,支持所有操作完成后再查询;不支持边操作边查询;
  • 对于本题来说,对于每对(p,q),令 x = p-q,如果X属于[0,x-1],那么需要操作一次,要将[0,x-1]区域全部加1;如果X属于[x+1,mx],也只需要操作一次,要将[x+1,mx]区域全部加1;如果X属于[mx+1,k],那么需要操作2次,要将[mx+1,k]区域全部加2
  • 如果要计算每个X对应的操作次数,就是算差分数组的前缀和
class Solution {
    public int minChanges(int[] nums, int k) {
        int n = nums.length;
        int[] d = new int[k+2];
        for(int i=0; i<n/2; i++){
            int p = nums[i], q = nums[n-i-1];
            if(p > q){
                int t = p;
                p = q;
                q = t;
            }
            int x = q - p;
            int mx = Math.max(q, k-p);
            //[0, x-1]范围所有数 +1
            d[0]++;
            d[x]--;
            //[x+1, mx]范围所有数 +1
            d[x+1]++;
            d[mx+1]--;
            //[mx+1, k]范围所有数 +2
            d[mx+1]+=2;
        }   
        int ans = n, pre = 0;
        for(int v : d){
            pre += v;
            ans = Math.min(ans, pre);
        }
        return ans;
    }
}

四,3225. 网格图操作后的最大分数

本题讲O(n^4)的解法,我们可以将原问题转换成一个与原问题相同的子问题,原问题:求 j 列网格图的最大分数;子问题:在知道最后一列黑格子的高度后,那么剩下的就是求 j-1 列网格图的最大分数,依次类推....

我们要求当前第 j 列所能得到的分数,必须要知道第 j+1 列和 j-1 列的黑格子的高度,所以可以这样定义dfs(j,cur,pre):在第 j 列黑格子高度为 cur,第 j+1 列黑格子高度为 pre 时,[0,j]列网格图的最大分数。还剩下第 j-1 列黑格子的高度,我们可以在dfs中枚举。

代码如下:

class Solution {
    public long maximumScore(int[][] grid) {
        int n = grid.length;
        long[][] preSum = new long[n+1][n];//每列的前缀和
        for(int i=0; i<n; i++){
            for(int j=0; j<n; j++){
                preSum[i+1][j] = preSum[i][j] + grid[i][j];
            }
        } 
        memo = new long[n+1][n+1][n+1];
        for(int i=0; i<n+1; i++){
            for(int j=0; j<n+1; j++){
                Arrays.fill(memo[i][j], -1);
            }
        }
        long ans = 0;
        //枚举n-1列的高度
        for(int i=0; i<=n; i++){
            ans = Math.max(ans, dfs(n-1,i,0,preSum));
        }
        return ans;
    }
    long[][][] memo;
    //dfs(j列, j列的高度, j+1列的高度)
    long dfs(int j, int cur, int pre, long[][] preSum){
        if(j == 0) return pre > cur ? preSum[pre][0]-preSum[cur][0]:0;
        if(memo[j][cur][pre] != -1) return memo[j][cur][pre];
        int n = preSum.length-1;
        long res = 0;
        //枚举j-1列的高度
        for(int nxt=0; nxt<=n; nxt++){
            long s = Math.max(nxt, pre) > cur ? preSum[Math.max(nxt,pre)][j]-preSum[cur][j] : 0;
            res = Math.max(res, dfs(j-1,nxt,cur,preSum)+s);
        }
        return memo[j][cur][pre] = res;
    }
}

在此贴一个O(n^3)的解法:

class Solution {
    public long maximumScore(int[][] grid) {
        int n = grid.length;
        long[][] preSum = new long[n+1][n];
        for(int i=0; i<n; i++){
            for(int j=0; j<n; j++){
                preSum[i+1][j] = preSum[i][j] + grid[i][j];
            }
        } 
        memo = new long[n+1][n+1][2];
        for(int i=0; i<n+1; i++){
            for(int j=0; j<n+1; j++){
                Arrays.fill(memo[i][j], -1);
            }
        }
        long ans = 0;
        //枚举n-1列的高度
        for(int i=0; i<=n; i++){
            ans = Math.max(ans, dfs(n-2,i,0,preSum));
        }
        return ans;
    }
    long[][][] memo;
    //dfs(j列, j+1列的高度, j+1列的高度 < j+2列的高度)
    long dfs(int j, int pre, int dec, long[][] preSum){
        if(j < 0) return 0;
        if(memo[j][pre][dec] != -1) return memo[j][pre][dec];
        int n = preSum.length-1;
        long res = 0;
        //枚举j-1列的高度
        for(int cur=0; cur<=n; cur++){
            if(cur == pre){
                res = Math.max(res, dfs(j-1,cur,0,preSum));
            }else if(cur < pre){
                res = Math.max(res, dfs(j-1,cur,1,preSum)+preSum[pre][j]-preSum[cur][j]);
            }else if(dec == 0){
                res = Math.max(res, dfs(j-1,cur,0,preSum)+preSum[cur][j+1]-preSum[pre][j+1]);
            }else if(pre == 0){
                res = Math.max(res, dfs(j-1,cur,0,preSum));
            }
        }
        return memo[j][pre][dec] = res;
    }
}

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
LeetCode-Editor是一种在线编码工具,它提供了一个用户友好的界面编写和运行代码。在使用LeetCode-Editor时,有时候会出现乱码的问题。 乱码的原因可能是由于编码格式不兼容或者编码错误导致的。在这种情况下,我们可以尝试以下几种解决方法: 1. 检查文件编码格式:首先,我们可以检查所编辑的文件的编码格式。通常来说,常用的编码格式有UTF-8和ASCII等。我们可以将编码格式更改为正确的格式。在LeetCode-Editor中,可以通过界面设置或编辑器设置来更改编码格式。 2. 使用正确的字符集:如果乱码是由于使用了不同的字符集导致的,我们可以尝试更改使用正确的字符集。常见的字符集如Unicode或者UTF-8等。在LeetCode-Editor中,可以在编辑器中选择正确的字符集。 3. 使用合适的编辑器:有时候,乱码问题可能与LeetCode-Editor自身相关。我们可以尝试使用其他编码工具,如Text Editor、Sublime Text或者IDE,看是否能够解决乱码问题。 4. 查找特殊字符:如果乱码问题只出现在某些特殊字符上,我们可以尝试找到并替换这些字符。通过仔细检查代码,我们可以找到导致乱码的特定字符,并进行修正或替换。 总之,解决LeetCode-Editor乱码问题的方法有很多。根据具体情况,我们可以尝试更改文件编码格式、使用正确的字符集、更换编辑器或者查找并替换特殊字符等方法来解决这个问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

一叶祇秋

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

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

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

打赏作者

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

抵扣说明:

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

余额充值