Leetcode周赛复盘——第 71 场力扣双周赛与第 279 场力扣周赛

双周赛:

5984. 拆分数位后四位数字的最小和

class Solution:
    def minimumSum(self, num: int) -> int:
        a, b, c, d = sorted(list(map(int, str(num))))
        return 10 * (a + b) + c + d

str(num)得到字符串序列,然后用map函数对序列的每个字符转换为数字,最后变为列表并且排序,最小的两个数 a、b 一定在十位所以乘10,个位则是 c 和 d。

5985. 根据给定数字划分数组

我的:

class Solution:
    def pivotArray(self, nums: List[int], pivot: int) -> List[int]:
        s = []
        e = []
        l = []
        for i in nums:
            if i < pivot:
                s.append(i)
            elif i == pivot:
                e.append(i)
            else:
                l.append(i)
        return s+e+l

大佬的:

class Solution:
    def pivotArray(self, nums: List[int], pivot: int) -> List[int]:
        ans = []
        for x in nums:
            if x < pivot:
                ans.append(x)
        for x in nums:
            if x == pivot:
                ans.append(x)
        for x in nums:
            if x > pivot:
                ans.append(x)
        return ans

区别不大,我是用三个列表分别记录小于、等于和大于 pivot 的数,然后把它们加起来。当然也可以循环 nums 三次,依次添加三种数进入 ans 中。

5986. 设置时间的最少代价

class Solution:
    def minCostSetTime(self, startAt: int, moveCost: int, pushCost: int, targetSeconds: int) -> int:
        ans = 10**9 
        for tmp in range(10000):  # 0000 到 9999 即所有情况
            a = list(map(int, str(tmp)))
            last = startAt
            need = 0
            for x in a:
                if x != last:
                    need += moveCost
                    last = x
                need += pushCost
            if tmp // 100 * 60 + tmp % 100 == targetSeconds:  # 正好是目标时间
                ans = min(ans, need)
        return ans

这题的基本思路是分类讨论,但是有点复杂。大佬的思路简单粗暴,直接枚举四个数字的所有情况,计算其代价,如果这四个数字对应的正好是目标时间,则比较其代价与当前最少代价,更新最少代价。

5987. 删除元素后和的最小差值

class Solution:
    def minimumDifference(self, nums: List[int]) -> int:
        n = len(nums) // 3
        
        left = [0 for _ in range(3 * n + 1)]        #左侧最小的n个数的和
        right = [0 for _ in range(3 * n + 1)]       #右侧最大的n个数的和
        
        l_max = []                          #每次要删除那个最大的数
        for i in range(3 * n):
            left[i + 1] = left[i] + nums[i]
            heapq.heappush(l_max, -1 * nums[i]) # 最大堆
            if n <= i:    # 堆中最多有 n 个元素,一旦超过就开始 pop
                left[i + 1] -= -1 * l_max[0]   # 最大的数会被 pop,所以要减去
                heapq.heappop(l_max)  # 删除堆中最大的数
        
        r_min = []                          #每次要删除那个最小的数
        for i in range(3 * n - 1, -1, -1):
            right[i] = right[i + 1] + nums[i]
            heapq.heappush(r_min, nums[i])  # 最小堆
            if i < 2 * n:  # 堆中最多有 n 个元素,一旦超过就开始 pop
                right[i] -= r_min[0]  # 最小的数会被 pop,所以要减去
                heapq.heappop(r_min)  # 删除堆中最小的数
        
        res = float('inf')
        for i in range(n, 2 * n + 1):  # 枚举分割点
            cur = left[i] - right[i]   # 前面部分减后面部分的值
            res = min(res, cur)
        return res

周赛

6000. 对奇偶下标分别排序

我的:

class Solution:
    def sortEvenOdd(self, nums: List[int]) -> List[int]:
        n = len(nums)
        odds = [nums[i] for i in range(n) if i % 2 == 1]
        evens = [nums[i] for i in range(n) if i % 2 == 0]
        odds.sort(reverse=True)
        evens.sort()
        ans = []
        for i in range(n):
            if i % 2 == 0:
                ans.append(evens[i // 2])
            else:
                ans.append(odds[(i-1) // 2])
        return ans

大佬的:

class Solution:
    def sortEvenOdd(self, nums: List[int]) -> List[int]:
        a = sorted(nums[0::2])
        b = sorted(nums[1::2], reverse=True)
        to_ret = []
        while len(a)+len(b) > 0 :
            if len(a) > 0 :
                to_ret.append(a.pop(0))
            if len(b) > 0 :
                to_ret.append(b.pop(0))
        return to_ret

优化点:1、取奇偶下标的元素不需要判断下标的奇偶,只需要设置步长为 2 ,起点为 0、1即可;2、排序应习惯用 sorted ,可以少写一行;3、要从头开始取元素,可以用 pop(0)

6001. 重排数字的最小值

我的:

class Solution:
    def smallestNumber(self, num: int) -> int:
        if num < 0:
            num_list = list(map(int, str(num)[1:]))
            num_list.sort(reverse=True)
            ans = 0
            for i in range(len(num_list)):
                ans = ans * 10 + num_list[i]
            ans = -ans
        elif num == 0:
            ans = 0
        else:
            num_list = list(map(int, str(num)))
            num_list.sort()
            num_zeros = num_list.count(0)
            ans = 0
            if num_zeros == 0:
                for i in range(len(num_list)):
                    ans = ans * 10 + num_list[i]
            else:
                ans = num_list[num_zeros]
                for i in range(num_zeros):
                    ans = ans * 10
                for i in range(num_zeros+1, len(num_list)):
                    ans = ans * 10 + num_list[i]
        return ans

大佬的:

class Solution:
    def smallestNumber(self, num: int) -> int:
        if num == 0 :
            return num
        if num < 0 :
            return -int(''.join(sorted(str(num)[1:], reverse=True)))
        if num > 0 :
            num = str(num)
            ct = len([1 for t in num if t == '0'])
            num = sorted([t for t in num if not t == '0'])
            return int(num[0] + '0'*ct + ''.join(num[1:]))

虽然都是分类讨论找规律,但是在表达上我还是不够简洁。实际上就三种情况:num 等于 0,则返回 0;num 小于 0,则按照数字从大到小返回;num 大于 0,则取最小的正数作为第一个数,然后跟 0,最后是其余正数。

6002. 设计位集

class Bitset:

    def __init__(self, size: int):
        self.size = size
        self.listt = [0] * size
        self.vcount = 0   # 记录 1 的个数
        self.isflip = False # 记录是否翻转

    def fix(self, idx: int) -> None:
        if not self.isflip :
            if not self.listt[idx] == 1 :
                self.vcount += 1
            self.listt[idx] = 1
        else :
            if not self.listt[idx] == 0 :
                self.vcount += 1
            self.listt[idx] = 0

    def unfix(self, idx: int) -> None:
        if not self.isflip :
            if not self.listt[idx] == 0 :
                self.vcount -= 1
            self.listt[idx] = 0
        else :
            if not self.listt[idx] == 1 :
                self.vcount -= 1
            self.listt[idx] = 1

    def flip(self) -> None:
        self.isflip = not self.isflip
        self.vcount = self.size - self.vcount

    def all(self) -> bool:
        return self.vcount == self.size

    def one(self) -> bool:
        return self.vcount > 0

    def count(self) -> int:
        return self.vcount

    def toString(self) -> str:
        if not self.isflip :
            return ''.join([str(t) for t in self.listt])
        else :
            return ''.join([str(1-t) for t in self.listt])

这题很容易超时,必须优化,而优化的点主要是两个:1、翻转操作不需要真的翻转,只需要用一个布尔标志记录是否处于翻转状态即可;2、由于初始时全为 0,所以在赋值 1 时可以用一个变量记录 1 出现的次数,这样就不用每次都计算有多少个 1 了。

6003. 移除所有载有违禁货物车厢所需的最少时间

正统的做法是动态规划,参考这篇题解

class Solution:
    def minimumTime(self, s: str) -> int:
        n = len(s)
        suf = [0] * (n + 1)
        for i in range(n - 1, -1, -1):
            suf[i] = suf[i + 1] if s[i] == '0' else min(suf[i + 1] + 2, n - i)
        ans = suf[0]
        pre = 0
        for i, ch in enumerate(s):
            if ch == '1':
                pre = min(pre + 2, i + 1)
                ans = min(ans, pre + suf[i + 1])
        return ans

另外有一种做法挺有意思,如图所示:
Leetcode周赛复盘——第 71 场力扣双周赛与第 279 场力扣周赛_第1张图片

class Solution:
    def minimumTime(self, s: str) -> int:
        lists = [1 if i == "1" else -1 for i in s]
        for i in range(1, len(lists)):
            if lists[i - 1] < 0:
                lists[i] += lists[i - 1]
        return len(lists) + min(min(lists), 0)

你可能感兴趣的:(Leetcode周赛,leetcode,算法,排序算法,数据结构,python)