leetcode第219场字节跳动周赛总结

leetcode第219场周赛总结

这次的周赛后两道题都是动态规划的,最后一题想复杂了 没做出来,其实也没有那么难

第一题

题目链接: 比赛中的配对次数.
在这里插入图片描述解题思路:
看图说话型题目,没什么好写的

class Solution {
    public int numberOfMatches(int n) {
        if(n == 1) return 0;
        int ans = 0;
        while(n >= 2){
            ans += n / 2;
            n = (n + 1) / 2;
        }
        return ans;
    }
}

第二题

十-二进制数的最少数目

题目链接: 十-二进制数的最少数目.
在这里插入图片描述
解题思路:
题目有点难懂,仔细看的话就觉得很简单了。十-二进制意思就是每一个位上都只能放1或者0,但是这个数还是十进制的。比如1001就是十-二进制,但他代表的是一千零1。
所以因为每一位都可以是1/0,我们最多用9个这样的十-二进制数就可以表示每个标准10进制数,于是就变成了求字符串中最大的数字,返回即可。

class Solution {
    public int minPartitions(String n) {
        int ans = 0;
        for(char c: n.toCharArray()){
            if(c - '0' > ans){
                ans = c - '0';
            }
        }
        return ans;
    }
}

第三题

题目链接: 石子游戏 VII.
在这里插入图片描述
解题思路:
   如果大家和我一样,是个身经百战的笨比,这道题应该不陌生了,很典型的动态规划题。这道题和石子游戏一几乎一样的解题思路,但这也是有个前提:
   爱丽丝总是能赢,石子没有负数
   因为没有负数,鲍勃的策略就从缩小分差变成了拿到最大的得分(因为他怎么都赢不了,所以不用考虑让分给爱丽丝),如果有正负,那么情况就变了。
   思路很正常,典型的区间从小到大进行状态转移,因为要求区间中的和,所以要获取前缀和的数组。
  dp[i][j]代表区间i - j上可以得到的最小分差(其实就是此时某个人选择时可以得到的最大得分),因为我只能选两边的石子,所以当处于i - j这个区间时,得到的分差就等于选择i 得到的分差选择j得到分差中的最大值,为什么是最大呢?因为两位的策略都是扩大自己的得分(爱丽丝是题目所述,鲍勃是迫不得已)
  于是转移方程就出来了:
  区间[i, j]的最小差 (最大得分)= max(选 i 的得分 - 剩下区间里下一个人的得分,选j的得分 - 剩下区间里下一个人的得分)

class Solution {
    public int stoneGameVII(int[] stones) {
        int[] preAdd = new int[stones.length];
        preAdd[0] = stones[0];
        for(int i = 1;i<stones.length;i++) {
            preAdd[i] = preAdd[i - 1] + stones[i];
        }
        int[][] dp = new int[stones.length][stones.length];
        for (int len = 0;len < stones.length;len ++){
            for(int i = 0;i< stones.length - len;i++){
                if(len == 0) dp[i][len + i] = 0;
                else {
                    int choose_left = preAdd[len + i] - preAdd[i];//选择i能拿到的分数
                    int choose_right = i == 0 ?preAdd[i + len - 1] : preAdd[i + len - 1] - preAdd[i - 1]; //选择J能拿到的分数,要考率i是否为0的情况
                    dp[i][len + i] = Math.max(choose_left - dp[i + 1][len + i],  choose_right- dp[i][i + len - 1]);//最后的分差等于选择i能拿到的分数减去[i+1,j]的分差 和 选择j能拿到的分数减去[i, j- 1]的分差 中的最大值
                }
            }
        }
        return dp[0][stones.length -1 ];
    }
}

第四题

题目链接: 堆叠长方体的最大高度.
在这里插入图片描述
解题思路:
  这道题的解题点是长,宽,高三个维度都要大于才可以堆叠。于是我们就想到了排序,因为长方体可以旋转,所以三个维度可以任意转换。所以首先我们对每个长方体三个维度按照大小排序,排完序之后再按照每个长方体最大的那个边对所有长方体排序
  这样的话就意味着排完序之后,只能把排在前面的长方体堆在排在后面的长方体上,后面长方体的不能堆在前面的长方体上面(除非完全一样)。
  然后我们就得到了这样一个数组[[a1,a2,a3],[b1,b2,b3],[c1,c2,c3]…]
其中 a3>=a2>=a1, b3>=b2>=b1,  c3>=c2>=c1, c3>=b3>=a3
  然后这个问题就变成了标准的动态规划问题,我们从小的长方体开始遍历,找出以这个长方体为底座的最大高度。
  dp[j]代表以这个长方体为底座的最大高度。
  每往后历遍一个长方体j,就对前面已经历遍的长方体i进行判断,如果可以堆在长方体j上,则更新dp[j] = max(dp[j], dp[i] + H[j])。最后输出dp数组中的最大值即可。
  最后的问题,每个长方体的高度用哪个边呢?答案很简单,用最长的那个,因为堆叠的条件是长,宽,高三个维度都要大于才可以堆叠,既然都大于,为了最大化高度,肯定是最高的立起来比较好嘛。

  比赛的时候我还在纠结dp是不是选和不选的dp,搞的没写出来

class Solution {
    public int maxHeight(int[][] cuboids) {
        for (int[] arr : cuboids) {
            Arrays.sort(arr);
        }
        Arrays.sort(cuboids, new Comparator<int[]>() {
            @Override
            public int compare(int[] o1, int[] o2) {
                if (o1[2] == o2[2]) {
                    if (o1[1] == o2[1]) {
                        return o1[0] - o2[0];
                    } else {
                        return o1[1] - o2[1];
                    }
                } else {
                    return o1[2] - o2[2];
                }
            }
        });
        int ans = 0;
        int[] dp = new int[cuboids.length];
        for (int i = 0;i<cuboids.length;i++){
            dp[i] = cuboids[i][2];
            for(int j = 0;j<i;j++){
                if (compare(cuboids[i],cuboids[j])){
                    dp[i] = Math.max(dp[i], dp[j] + cuboids[i][2]);
                }
            }
            ans = Math.max(ans, dp[i]);
        }
        return ans;
    }
    public boolean compare(int[] arr1, int[] arr2){
        if(arr1[2] >= arr2[2]){
            if(arr1[1] >= arr2[1]){
                return arr1[0] >= arr2[0];
            }else {
                return false;
            }
        }else {
            return false;
        }
    }
}

总结

  这次的最后一题是属于正常范畴的,差一点就写出来了,有点可惜,时间结束之后才想明白。感觉除了一些很变态的图论题或者奇奇怪怪的dp题,其他的题像我这种一般人也可以写一下。
文中的题目描述和图片均来自于leetcode
链接: link.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值