Leetcode 第 219 场周赛题解 (Python)

Leetcode 第 219 场周赛题解

周赛日期:2020/12/13

题目1: 5625. 比赛中的配对次数 难度: 简单

给你一个整数 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

题解:模拟

上手题,直接上模拟

class Solution:
    def numberOfMatches(self, n: int) -> int:
        res = 0
        while n != 1:
            if n % 2 == 0:
                res += n // 2
                n //= 2
            else:
                res += n // 2
                n = (n+1) // 2
        return res

题目2:1689. 十-二进制数的最少数目 难度: 中等

如果一个十进制数字不含任何前导零,且每一位上的数字不是 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 不含任何前导零并总是表示正整数

题解:简单技巧

 

直接找十进制中每一位的最大值就可以得到结果。

class Solution:
    def minPartitions(self, n: str) -> int:
        res = 0
        for c in n:
            res = max(res, ord(c)-ord('0'))
        return res

 

题目3: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[i][j]定义为区间[i,j]我们要的结果,在区间[i, j],dp[i][j] = 先手的总分 - 后手的总分。
如果dp[i][j]这个区间当前是鲍勃操作,那么鲍勃的得分一定最大。
选择去掉stones[i]后当前的分数为sum(stones[i + 1], stones[j]).
那么区间[i + 1, j]鲍勃的得分是多少呢?不用管它,dp[i + 1][j]一定为对手爱丽丝作为先手得到的结果,因为谁先手谁的得分最大,则dp[i + 1][j] = 爱丽丝得分 - 鲍勃的得分。
sum(stones[i + 1], stones[j]) - dp[i + 1][j]
= 鲍勃当前操作得分 - (爱丽丝的总分 - 鲍勃的总分)
= 鲍勃当前操作得分 + 鲍勃的总分 - 爱丽丝的总分
= 鲍勃新的总分 - 爱丽丝的总分 > 0(谁先手谁最大)。
如果去掉stones[j]则原理同上.
如果当前dp[i][j]是爱丽丝,则将上面的叙述中爱丽丝和鲍勃名字互换。
对于爱丽丝我们很好理解为什么要最大化
dp[i][j] = max(sum(stones[i + 1], stones[j]) - dp[i + 1][j], sum(stones[i], stones[j - 1]) - dp[i][j - 1]);
那么鲍勃为什么也要最大化dp[i][j]呢,因为爱丽丝先手,鲍勃必输,题目给出了。所以只有当鲍勃操作时dp[i][j]最大,才能让爱丽丝操作时得到的结果最小,满足鲍勃的野心
爱丽丝当前操作得分 - (鲍勃的总分 - 爱丽丝的总分)(鲍勃操作时的最大化差值)

class Solution:
    def stoneGameVII(self, stones: List[int]) -> int:
        n = len(stones)
        dp = [[0]*(n+1) for _ in range(n+1)]
        s = [0]*(n+1)
        for i in range(1, n+1):
            s[i] += s[i-1] + stones[i-1]
        for k in range(1, n):
            for l in range(1, n-k+1):
                r = l + k
                dp[l][r] = max(s[r-1] - s[l-1] - dp[l][r-1], s[r]- s[l] - dp[l+1][r])
        return dp[1][n]

题目4:1691. 堆叠长方体的最大高度  难度: 困难

给你 n 个长方体 cuboids ,其中第 i 个长方体的长宽高表示为 cuboids[i] = [widthi, lengthi, heighti](下标从 0 开始)。请你从 cuboids 选出一个 子集 ,并将它们堆叠起来。

如果 widthi <= widthj 且 lengthi <= lengthj 且 heighti <= heightj ,你就可以将长方体 i 堆叠在长方体 j 上。你可以通过旋转把长方体的长宽高重新排列,以将它放在另一个长方体上。

返回 堆叠长方体 cuboids 可以得到的 最大高度 。

Leetcode 第 219 场周赛题解 (Python)_第1张图片

示例 1:

输入:cuboids = [[50,45,20],[95,37,53],[45,23,12]]
输出:190
解释:
第 1 个长方体放在底部,53x37 的一面朝下,高度为 95 。
第 0 个长方体放在中间,45x20 的一面朝下,高度为 50 。
第 2 个长方体放在上面,23x12 的一面朝下,高度为 45 。
总高度是 95 + 50 + 45 = 190 。
示例 2:

输入:cuboids = [[38,25,45],[76,35,3]]
输出:76
解释:
无法将任何长方体放在另一个上面。
选择第 1 个长方体然后旋转它,使 35x3 的一面朝下,其高度为 76 。
示例 3:

输入:cuboids = [[7,11,17],[7,17,11],[11,7,17],[11,17,7],[17,7,11],[17,11,7]]
输出:102
解释:
重新排列长方体后,可以看到所有长方体的尺寸都相同。
你可以把 11x7 的一面朝下,这样它们的高度就是 17 。
堆叠长方体的最大高度为 6 * 17 = 102 。
 

提示:

n == cuboids.length
1 <= n <= 100
1 <= widthi, lengthi, heighti <= 100

题解:贪心+最长上升子序列

这题上来可以发现比较像最长上升子序列(动态规划)。但对于动态规划来说,前后数据的关系必须要确定,这里题目中允许旋转会导致一种不确定的情况,所以我们要尽可能让数据之间的顺序固定。

为了固定顺序,我们可以使用贪心来保准数据的顺序,题目为了高度最高,我们不妨把所有的长方形最长的边最为高,然后第二大的作为长,最短的作为宽,这样就可以确定顺序。

做法如下:

1、每个长方体内长宽高降序排序。

2、长方体之间按照高进行降序排序。

3、使用动态规划求解(最长上升子序列)

class Solution:
    def maxHeight(self, cuboids: List[List[int]]) -> int:
        n = len(cuboids)
        for i in range(n):
            cuboids[i] = sorted(cuboids[i], key=lambda x: -x)
        dp = [0]*(n)
        max_h = 0
        cuboids.sort(key=lambda x: [-x[0], -x[1], -x[2]])
        for i in range(n):
            dp[i] = cuboids[i][0]
            for j in range(i):
                if cuboids[j][1] >= cuboids[i][1] \
                        and cuboids[j][2] >= cuboids[i][2]:
                    dp[i] = max(dp[i], dp[j]+cuboids[i][0])
            max_h = max(dp[i], max_h)
        return max_h

你可能感兴趣的:(Leetcode周赛,每日算法题,动态规划,算法,数据结构,leetcode)