[LeetCode周赛复盘] 第 295 场周赛20220529

一、本周周赛总结

  • 补一下上周的周赛。
  • 比赛时只做了前两题,被第三题卡没了,最后剩五分钟才想起来看看最后一题。
  • 结果最后一题就是最短路模板题,真的会谢。

二、 [Easy] 2287. 重排字符形成目标字符串

链接: 2287. 重排字符形成目标字符串

1. 题目描述

给你两个下标从 0 开始的字符串 s 和 target 。你可以从 s 取出一些字符并将其重排,得到若干新的字符串。

从 s 中取出字符并重新排列,返回可以形成 target 的 最大 副本数。

2. 思路分析

定级Easy。
统计target中对应字符的数量在s中有几倍数。

3. 代码实现

class Solution:
 class Solution:
    def rearrangeCharacters(self, s: str, target: str) -> int:
        d = collections.defaultdict(int)
        for c in s:
            d[c] += 1
        
        ans = 1e9
        d2 = collections.defaultdict(int)
        for c in target:
            d2[c] += 1
        for c in target:      
            ans = min(ans, d.get(c,0)//d2.get(c,0) )
        return ans

三、[Medium] 2288. 价格减免

链接: 2288. 价格减免

1. 题目描述

句子 是由若干个单词组成的字符串,单词之间用单个空格分隔,其中每个单词可以包含数字、小写字母、和美元符号 ‘$’ 。如果单词的形式为美元符号后跟着一个非负实数,那么这个单词就表示一个价格。

例如 “$100”、“$23” 和 “ 6.75 " 表 示 价 格 , 而 " 100 " 、 " 6.75" 表示价格,而 "100"、" 6.75""100""” 和 “2$3” 不是。
注意:本题输入中的价格均为整数。

给你一个字符串 sentence 和一个整数 discount 。对于每个表示价格的单词,都在价格的基础上减免 discount% ,并 更新 该单词到句子中。所有更新后的价格应该表示为一个 恰好保留小数点后两位 的数字。

返回表示修改后句子的字符串。

2. 思路分析

定级Medium。
模拟题,拆分后修改即可。

3. 代码实现

class Solution:
    def discountPrices(self, sentence: str, discount: int) -> str:
        words = sentence.split(' ')
        ans = []
        for word in words:
            if word[0] == '$' and word[1:].isdigit() and float(word[1:]) >= 0:
                price = float(word[1:])
                ans.append(f'${price*0.01*(100-discount):.2f}') 
                continue                                    
            ans.append(word) 
        return ' '.join(ans)

四、[Medium] 2289. 使数组按非递减顺序排列

链接: 2289. 使数组按非递减顺序排列

1. 题目描述

给你一个下标从 0 开始的整数数组 nums 。在一步操作中,移除所有满足 nums[i - 1] > nums[i] 的 nums[i] ,其中 0 < i < nums.length 。

重复执行步骤,直到 nums 变为 非递减 数组,返回所需执行的操作数。

2. 思路分析

这题定级Medium就离谱,直接被卡死。
思路是单调栈+dp,和一般单调栈应用不同之处在于:

3. 代码实现

class Solution:
    def totalSteps(self, nums: List[int]) -> int:
        """
        1.每个数只要前边有比它大的数,一定会被删除。
        2.每个数都会被他前边更大的数删除,但不一定是最近那个,因为那个数可能会被自己前边的大数删掉
          如[5,4,1,2], 2这个数不会被4删掉,因为4会被5删掉。
          但这没关系,这相当于5代替了4的位置。
        3.因此每个数被删除的时间只取决于它前边比它小的数能挡几轮:
        4.换言之:每个数被删除的时间dp[i]=max{dp[j]+1|k<j<i,k是j前边第一个比它大的数的位置},k可以用单调栈在O(n)的时间算出
        5.但这个方法是n^2的,TLE已试        .
        6.实际上步骤4中的每个j都是在单调栈构建过程中pop的那个数,那么可以在这一步同时计算dp[i]。
        7.那么是否存在dp[i]因更前方的pop而漏算的情况?
            [7,1,2,5,3,4,6],观察这个案例,5的删除次数只取决于1,2的删除次数max+1。
            而6,按步骤4的推算应该计算1,2,5,3,4每个数的次数max+1,
            实际上 dp[5] = max(dp[1,2]+1),因此不需要计算前边1,2,只需要计算5以及以后的数,即5,3,4,
            这三个数恰好是构造单调栈时,入栈6时需要pop的数。
            因此不存在漏算。
        8.额外的,每个数i若入栈前把栈删空了,说明这个数i前边没有比它更大的数,他不会被删除,dp[i] = 0
        """
        n = len(nums)
        stack = []
        dp=[0]*n
        for i in range(n):
            if i > 0 and nums[i] < nums[i-1]:
                dp[i] = 1
            while stack and nums[stack[-1]] <= nums[i]:  # 构造单调递减栈,需要把栈顶比本数小的数都干掉
                dp[i] = max(dp[i],dp[stack[-1]]+1)
                stack.pop()           
            if not stack:
                dp[i] = 0 
            stack.append(i) 

        return max(dp)

五、[Hard] 2290. 到达角落需要移除障碍物的最小数目

链接: 2290. 到达角落需要移除障碍物的最小数目

1. 题目描述

给你一个下标从 0 开始的二维整数数组 grid ,数组大小为 m x n 。每个单元格都是两个值之一:

0 表示一个 空 单元格,
1 表示一个可以移除的 障碍物 。
你可以向上、下、左、右移动,从一个空单元格移动到另一个空单元格。

现在你需要从左上角 (0, 0) 移动到右下角 (m - 1, n - 1) ,返回需要移除的障碍物的 最小 数目。

示例 1:
在这里插入图片描述

输入:grid = [[0,1,1],[1,1,0],[1,1,0]]
输出:2
解释:可以移除位于 (0, 1) 和 (0, 2) 的障碍物来创建从 (0, 0) 到 (2, 2) 的路径。
可以证明我们至少需要移除两个障碍物,所以返回 2 。
注意,可能存在其他方式来移除 2 个障碍物,创建出可行的路径。
示例 2:
在这里插入图片描述

输入:grid = [[0,1,0,0,0],[0,1,0,1,0],[0,0,0,1,0]]
输出:0
解释:不移除任何障碍物就能从 (0, 0) 到 (2, 4) ,所以返回 0 。

2. 思路分析

这题虽然定级Hard
然而是就是最短路模板
参考 [LeetCode解题报告] 6081. 到达角落需要移除障碍物的最小数目

3. 代码实现

class PriorityQueue:
    def __init__(self):
        self._queue = []
        self._index = 0  # 传入顺序
    def push(self, item, priority):
        heapq.heappush(self._queue, (priority, self._index, item))
        self._index += 1
    def pop(self):
        return heapq.heappop(self._queue)[-1]
    def __str__(self):
        return str(self._queue)
    def __len__(self):
        return len(self._queue)
class Solution:
    def minimumObstacles(self, grid: List[List[int]]) -> int:
        m,n = len(grid),len(grid[0])
        q = PriorityQueue()
        q.push((0,0,0),0)
        visited = {(0,0):0}
        while q:
            x,y,z =q.pop()
            if x == m-1 and y == n -1:
                return z
            
            for x1,y1 in [(x-1,y),(x+1,y),(x,y-1),(x,y+1)]:
                if not (0<=x1<m and 0<=y1<n):
                    continue
                if (x1,y1) not in visited or visited[(x1,y1)] > z+grid[x1][y1]:
                    visited[(x1,y1)] = z+grid[x1][y1]
                    q.push((x1,y1,visited[(x1,y1)]),visited[(x1,y1)])
        
        return -1

六、参考链接

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值