leetcode 219 周赛

1688. 比赛中的配对次数

给你一个整数 n ,表示比赛中的队伍数。比赛遵循一种独特的赛制:

如果当前队伍数是 偶数 ,那么每支队伍都会与另一支队伍配对。总共进行 n / 2 场比赛,且产生 n / 2 支队伍进入下一轮。
如果当前队伍数为 奇数 ,那么将会随机轮空并晋级一支队伍,其余的队伍配对。总共进行 (n - 1) / 2 场比赛,且产生 (n - 1) / 2 + 1 支队伍进入下一轮。
返回在比赛中进行的配对次数,直到决出获胜队伍为止。

示例 1:

输入:n = 7
输出:6
解释:比赛详情:

  • 第 1 轮:队伍数 = 7 ,配对次数 = 3 ,4 支队伍晋级。
  • 第 2 轮:队伍数 = 4 ,配对次数 = 2 ,2 支队伍晋级。
  • 第 3 轮:队伍数 = 2 ,配对次数 = 1 ,决出 1 支获胜队伍。
    总配对次数 = 3 + 2 + 1 = 6
    示例 2:

输入:n = 14
输出:13
解释:比赛详情:

  • 第 1 轮:队伍数 = 14 ,配对次数 = 7 ,7 支队伍晋级。
  • 第 2 轮:队伍数 = 7 ,配对次数 = 3 ,4 支队伍晋级。
  • 第 3 轮:队伍数 = 4 ,配对次数 = 2 ,2 支队伍晋级。
  • 第 4 轮:队伍数 = 2 ,配对次数 = 1 ,决出 1 支获胜队伍。
    总配对次数 = 7 + 3 + 2 + 1 = 13

提示:

1 <= n <= 200
1)最简单解法
共有n个队伍,一个冠军,需要淘汰n-1个 队伍。
每一场比赛淘汰一个队伍,因此进行了n-1场比赛。
所以共有n-1个配对。

class Solution {
    
    
    public int numberOfMatches(int n) {
    
    
        return n-1;
    }
}

2)

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

1689. 十-二进制数的最少数目

(2)如果一个十进制数字不含任何前导零,且每一位上的数字不是 0 就是 1 ,那么该数字就是一个 十-二进制数 。例如,101 和 1100 都是 十-二进制数,而 112 和 3001 不是。

给你一个表示十进制整数的字符串 n ,返回和为 n 的 十-二进制数 的最少数目。

示例 1:

输入:n = “32”
输出:3
解释:10 + 11 + 11 = 32
示例 2:

输入:n = “82734”
输出:8
示例 3:

输入:n = “27346209830709182346”
输出:9

提示:

1 <= n.length <= 105
n 仅由数字组成
n 不含任何前导零并总是表示正整数
解题思路:

脑筋急转弯题,将n的各个位分开来看,每次都将各个位中的最大数值位减一,以保证总位数不变,这样数目才会最少。
比如82734-10000=72734, 72734-10100=62634, 62634-10100=52534, 52534-10100=42434, 42434-10101=32333, 32333-10111=22222, 22222-11111=11111, 11111-11111=0, 共8次。

class Solution {
    
    
    public int minPartitions(String n) {
    
    
           int sum =0;
           for(int i =0;i<n.length();i++){
    
    
               if(n.charAt(i)-'0'>sum){
    
    
                   sum = n.charAt(i)-'0';
               }
               if(sum==9){
    
    
                   return 9;
               }
           }
           return sum;
    }
}

1690. 石子游戏 VII

石子游戏中,爱丽丝和鲍勃轮流进行自己的回合,爱丽丝先开始 。

有 n 块石子排成一排。每个玩家的回合中,可以从行中 移除 最左边的石头或最右边的石头,并获得与该行中剩余石头值之 和 相等的得分。当没有石头可移除时,得分较高者获胜。

鲍勃发现他总是输掉游戏(可怜的鲍勃,他总是输),所以他决定尽力 减小得分的差值 。爱丽丝的目标是最大限度地 扩大得分的差值 。

给你一个整数数组 stones ,其中 stones[i] 表示 从左边开始 的第 i 个石头的值,如果爱丽丝和鲍勃都 发挥出最佳水平 ,请返回他们 得分的差值 。

示例 1:

输入:stones = [5,3,1,4,2]
输出:6
解释:

  • 爱丽丝移除 2 ,得分 5 + 3 + 1 + 4 = 13 。游戏情况:爱丽丝 = 13 ,鲍勃 = 0 ,石子 = [5,3,1,4] 。
  • 鲍勃移除 5 ,得分 3 + 1 + 4 = 8 。游戏情况:爱丽丝 = 13 ,鲍勃 = 8 ,石子 = [3,1,4] 。
  • 爱丽丝移除 3 ,得分 1 + 4 = 5 。游戏情况:爱丽丝 = 18 ,鲍勃 = 8 ,石子 = [1,4] 。
  • 鲍勃移除 1 ,得分 4 。游戏情况:爱丽丝 = 18 ,鲍勃 = 12 ,石子 = [4] 。
  • 爱丽丝移除 4 ,得分 0 。游戏情况:爱丽丝 = 18 ,鲍勃 = 12 ,石子 = [] 。
    得分的差值 18 - 12 = 6 。
    示例 2:

输入:stones = [7,90,5,1,100,10,10,2]
输出:122

提示:

n == stones.length
2 <= n <= 1000
1 <= stones[i] <= 1000

解释
DP 数组定义为 dp[a][b] 为 Alice 在区间[a,b] Alice先手的收益和Bob的收益差值
也就是说dp[a][b] 是 游戏规定在 [a,b]区间:Alice 先手, dp[a][b] = Alice获取的最大收益值-Bob获取的最大收益值
边界值
只剩下一个
dp[a][a] Alice 拿了a,没有其余 因此是0

只剩下两个
dp[a][a+1] Alice 拿了小的,获取剩下的大值 Alice = max(stones[a],stones[a+1])
Bob过来发现剩下一个,拿走后不能获取值 bob = 0
dp[a][a+1] = Alice - bob = max(stones[a],stones[a+1])

其他情况
因此无非两种情况:
1.Alice 选择a,假设选择A的收益是SelectA
2.Alice 选择b,假设选择B的收益是SelectB
因此 dp[a][b] = max(selectA,selectB)

那么我们只需要计算selectA和selectB

selectB计算
首先,如果Alice 选择b的情况下,那么Bob也只有两个选项(选择a,或者b-1).
我们注意到,当bob选择某个完成后,又是Alice选择啦,因此一定是
这次bob选择后Alice的收益 + 剩下区间的dp值

这里画图理解

我们发现,Alice和bob获取的差值一定是bob选择的石头对应的值+剩余区间Alice先手的dp值,因此bob一定会选择小的让Alice的收益减少

bob 选a, Alice收益是stones[a]+dp[a+1][b-1]
bob 选b-1,Alice收益是stones[b-1]+dp[a][b-2]
bob 要让差距小,因此会选两者最小值
selectB = min(stones[a]+dp[a+1][b-1],stones[b-1]+dp[a][b-2])

selectA计算
与selectB计算相似,自己画图,结果是
min(stones[a+1]+dp[a+2][b],stones[b]+dp[a+1][b-1])
在这里插入图片描述

关键
想清楚博弈树,当Alice操作一定是增加差距,所以是max
当bob操作一定是减少差距,所以是min

代码如下


class Solution {
    
    
    public int stoneGameVII(int[] stones) {
    
    
        int n =  stones.length;
        int [] []dp = new int[n][n];
        for(int i = 1; i < n;i++){
    
    
            for(int j = i;j < n;j++){
    
    
                int a = j - i ;
                int b = j;
                if( a + 1 == b){
    
    
                    dp[a][b] = Math.max(stones[a],stones[b]);
                }else if(a + 2 == b){
    
    
                    if(stones[a]<stones[b]){
    
    
                        dp[a][b] = Math.min(stones[b],stones[b-1]);
                    }else{
    
    
                        dp[a][b] = Math.min(stones[a],stones[a+1]);
                    }
                }else{
    
    
                        int selectB = Math.min(stones[a]+dp[a+1][b-1],stones[b-1]+dp[a][b-2]);
                        int selectA = Math.min(stones[a+1]+dp[a+2][b],stones[b]+dp[a+1][b-1]);
                        dp[a][b] = Math.max(selectB,selectA);
                }
            }
        }
        return dp[0][n-1];  
    }
}

作者:spring-without-ns

猜你喜欢

转载自blog.csdn.net/qq_43688587/article/details/112724505