力扣周赛335
5839. 移除石子使总数最小
题目描述
给你一个整数数组 a ,数组 a 的长度为 2 * n ,且 n 是一个 偶数 。数组中有 n + 1 种不同的元素,其中有一个元素重复了 n 次。
你的任务是将 a 中 所有 重复了 n 次的元素移除,使得剩余的元素之和 最小 。
请你返回在完成任务后,数组 a 中剩余元素之和。
题目分析
这道题目的思路比较简单,就是找出重复了 n 次的元素,然后将其从数组中移除。剩余的元素之和就是答案。
为了找出重复了 n 次的元素,我们可以用一个哈希表来记录每个元素出现的次数,然后遍历哈希表,找到出现次数为 n 的元素。这个过程的时间复杂度是 O(n) ,空间复杂度是 O(n) 。
为了计算剩余元素之和,我们可以先求出数组中所有元素之和,然后减去重复元素乘以 n 。这个过程的时间复杂度是 O(n) ,空间复杂度是 O(1) 。
综上,总的时间复杂度是 O(n) ,空间复杂度是 O(n) 。
代码实现
class Solution:
def minStoneSum(self, a: List[int], n: int) -> int:
# 记录每个元素出现的次数
count = {}
for x in a:
count[x] = count.get(x, 0) + 1
# 找出重复了 n 次的元素
repeat = None
for x in count:
if count[x] == n:
repeat = x
break
# 计算所有元素之和
total = sum(a)
# 减去重复元素乘以 n
total -= repeat * n
# 返回剩余元素之和
return total
5840. 使字符串平衡的最少删除次数
题目描述
给你一个字符串 s ,它仅包含字符 'a' 和 'b' 。
你可以删除 s 中任意数目的字符,使得 s 平衡 。我们称 s 平衡的当不存在下标对 (i,j) 满足 i < j 且 s[i] = 'b' 且 s[j]= 'a' 。
请你返回使 s 平衡 的 最少 删除次数。
题目分析
这道题目的思路是使用一个栈来模拟删除操作,遍历字符串中的每个字符,如果栈为空或者栈顶元素和当前元素相同,就将当前元素入栈,否则就将栈顶元素出栈,表示删除了一对 'ba' 。最后栈中剩余的元素就是不能被删除的元素,其个数就是答案。
这个过程的时间复杂度是 O(n) ,空间复杂度是 O(n) ,其中 n 是字符串的长度。
代码实现
class Solution:
def minimumDeletions(self, s: str) -> int:
# 使用一个栈来模拟删除操作
stack = []
for x in s:
# 如果栈为空或者栈顶元素和当前元素相同,就将当前元素入栈
if not stack or stack[-1] == x:
stack.append(x)
# 否则就将栈顶元素出栈,表示删除了一对 'ba'
else:
stack.pop()
# 返回栈中剩余元素的个数
return len(stack)
5841. 找出到每个位置为止最长的有效障碍赛跑路线
题目描述
给你一个整数数组 obstacles ,表示由一些障碍组成的赛跑路线。每个 obstacles[i] 表示第 i 个障碍的高度。
如果某个单位长度的赛跑路线是 有效 的,那么它应该包含 三个 连续的障碍,且它们的高度 依次递增 或 依次递减 。
更正式地说,对于有效赛跑路线中的某个长度为 3 的子数组 obstacles[l], obstacles[l+1], obstacles[l+2] ,它们要么满足 obstacles[l] < obstacles[l+1] < obstacles[l+2] ,要么满足 obstacles[l] > obstacles[l+1] > obstacles[l+2] 。
返回一个数组 ans ,其中 ans[i] 是满足下面条件的最长有效赛跑路线的长度:
- 该赛跑路线的子数组为
obstacles[0], obstacles[1], ..., obstacles[i]。 - 如果不存在这样的有效赛跑路线,那么
ans[i]为-1。
题目分析
这道题目的思路是使用动态规划来记录到每个位置为止最长的有效赛跑路线的长度。我们可以用两个数组 up 和 down 来分别表示以递增和递减方式结束的最长有效赛跑路线的长度。对于每个位置 i ,我们有以下几种情况:
- 如果
obstacles[i] == obstacles[i-1],那么当前位置无法形成有效赛跑路线,所以up[i] = down[i] = -1。 - 如果
obstacles[i] > obstacles[i-1],那么当前位置可以和前一个位置形成递增关系,所以up[i] = down[i-1] + 1。如果前一个位置无法形成有效赛跑路线,那么当前位置也无法形成,所以如果down[i-1] == -1,那么up[i] = -1。同时,当前位置无法和前一个位置形成递减关系,所以down[i] = -1。 - 如果
obstacles[i] < obstacles[i-1],那么当前位置可以和前一个位置形成递减关系,所以down[i] = up[i-1] + 1。如果前一个位置无法形成有效赛跑路线,那么当前位置也无法形成,所以如果up[i-1] == -1,那么down[i] = -1。同时,当前位置无法和前一个位置形成递增关系,所以up[i] = -1。
最后,我们返回数组 ans ,其中 ans[i] = max(up[i], down[i]) 。如果数组为空或只有一个元素,我们返回空数组。
这个过程的时间复杂度是 O(n) ,空间复杂度是 O(n) ,其中 n 是数组的长度。
代码实现
class Solution:
def longestObstacleCourseAtEachPosition(self, obstacles: List[int]) -> List[int]:
# 特判空数组或只有一个元素的情况
if not obstacles or len(obstacles) == 1:
return []
# 初始化动态规划数组
n = len(obstacles)
up = [0] * n # 记录以递增方式结束的最长有效赛跑路线的长度
down = [0] * n # 记录以递减方式结束的最长有效赛跑路线的长度
# 遍历每个位置
for i in range(1, n):
# 如果当前障碍和前一个障碍相同,无法形成有效赛跑路线
if obstacles[i] == obstacles[i-1]:
up[i] = down[i] = -1
# 如果当前障碍大于前一个障碍,可以形成递增关系
elif obstacles[i] > obstacles[i-1]:
# 如果前一个位置可以形成有效赛跑路线,那么当前位置的递增长度等于前一个位置的递减长度加一
if down[i-1] != -1:
up[i] = down[i-1] + 1
# 否则,当前位置也无法形成有效赛跑路线
else:
up[i] = -1
# 当前位置无法形成递减关系
down[i] = -1
# 如果当前障碍小于前一个障碍,可以形成递减关系
else:
# 如果前一个位置可以形成有效赛跑路线,那么当前位置的递减长度等于前一个位置的递增长度加一
if up[i-1] != -1:
down[i] = up[i-1] + 1
# 否则,当前位置也无法形成有效赛跑路线
else:
down[i] = -1
# 当前位置无法形成递增关系
up[i] = -1
# 返回结果数组,其中每个元素是以递增或递减方式结束的最长有效赛跑路线的长度的最大值
ans = []
for i in range(n):
ans.append(max(up[i], down[i]))
return ans