[LeetCode周赛复盘] 第 296 场周赛20220605
一、本周周赛总结
- 几乎全是模拟题,除了第二题是一道同向双指针。
- 第二次打力扣周赛就ak了,这周的题好水啊。
- 前排的大佬真就做阅读理解呗,读完题=会了。
二、 [Easy] 6090. 极大极小游戏
链接: 6090. 极大极小游戏
1. 题目描述
给你一个下标从 0 开始的整数数组 nums ,其长度是 2 的幂。
对 nums 执行下述算法:
设 n 等于 nums 的长度,如果 n == 1 ,终止 算法过程。否则,创建 一个新的整数数组 newNums ,新数组长度为 n / 2 ,下标从 0 开始。
对于满足 0 <= i < n / 2 的每个 偶数 下标 i ,将 newNums[i] 赋值 为 min(nums[2 * i], nums[2 * i + 1]) 。
对于满足 0 <= i < n / 2 的每个 奇数 下标 i ,将 newNums[i] 赋值 为 max(nums[2 * i], nums[2 * i + 1]) 。
用 newNums 替换 nums 。
从步骤 1 开始 重复 整个过程。
执行算法后,返回 nums 中剩下的那个数字。
2. 思路分析
定级Easy。
按题意模拟即可。
3. 代码实现
class Solution:
def minMaxGame(self, nums: List[int]) -> int:
def dfs(nums):
n = len(nums)
if n == 1:
return nums[0]
new_nums = [0] * (n//2)
for i in range(len(new_nums)):
if i & 1 ==0:
new_nums[i] = min(nums[i*2],nums[i*2+1])
else:
new_nums[i] = max(nums[i*2],nums[i*2+1])
return dfs(new_nums)
return dfs(nums)
三、[Medium] 6091. 划分数组使最大差为 K
1. 题目描述
给你一个整数数组 nums 和一个整数 k 。你可以将 nums 划分成一个或多个 子序列 ,使 nums 中的每个元素都 恰好 出现在一个子序列中。
在满足每个子序列中最大值和最小值之间的差值最多为 k 的前提下,返回需要划分的 最少 子序列数目。
子序列 本质是一个序列,可以通过删除另一个序列中的某些元素(或者不删除)但不改变剩下元素的顺序得到。
2. 思路分析
定级Medium。
是这次周赛唯一有难度的题。
排序后用同向双指针分组即可。
3. 代码实现
class Solution:
def partitionArray(self, nums: List[int], k: int) -> int:
n = len(nums)
nums.sort()
ans = 0
l = r = 0
while l < n and r < n:
while r < n and nums[r] - nums[l] <= k:
r += 1
ans += 1
l = r
return ans
四、[Medium] 6092. 替换数组中的元素
链接: 6092. 替换数组中的元素
1. 题目描述
给你一个下标从 0 开始的数组 nums ,它包含 n 个 互不相同 的正整数。请你对这个数组执行 m 个操作,在第 i 个操作中,你需要将数字 operations[i][0] 替换成 operations[i][1] 。
题目保证在第 i 个操作中:
- operations[i][0] 在 nums 中存在。
- operations[i][1] 在 nums 中不存在。
请你返回执行完所有操作后的数组。
2. 思路分析
定级Medium。
按题意模拟即可,用一个字典记录每个数的下标。
由于题意operations限制,因此数组操作过程中不会出现一个数字同时出现在多个地方。
3. 代码实现
class Solution:
def arrayChange(self, nums: List[int], operations: List[List[int]]) -> List[int]:
pos = {v:k for k,v in enumerate(nums)}
for a,b in operations:
nums[pos[a]] = b
pos[b] = pos[a]
return nums
五、[Hard] 1640. 能否连接形成数组
链接: 1640. 能否连接形成数组
1. 题目描述
请你设计一个带光标的文本编辑器,它可以实现以下功能:
- 添加:在光标所在处添加文本。
- 删除:在光标所在处删除文本(模拟键盘的删除键)。
- 移动:将光标往左或者往右移动。
当删除文本时,只有光标左边的字符会被删除。光标会留在文本内,也就是说任意时候 0 <= cursor.position <= currentText.length 都成立。
请你实现 TextEditor 类:
- TextEditor() 用空文本初始化对象。
- void addText(string text) 将 text 添加到光标所在位置。添加完后光标在 text 的右边。
- int deleteText(int k) 删除光标左边 k 个字符。返回实际删除的字符数目。
- string cursorLeft(int k) 将光标向左移动 k 次。返回移动后光标左边 min(10, len) 个字符,其中 len 是光标左边的字符数目。
- string cursorRight(int k) 将光标向右移动 k 次。返回移动后光标左边 min(10, len) 个字符,其中 len 是光标左边的字符数目。
2. 思路分析
定级Hard。
然而是纯模拟题,不管是删除还是移动,提前判断是否越界,得出实际移动光标步数即可。
- 比赛时候看数据量小模拟过了,实际应该用两个栈对倒。
3. 代码实现
模拟
class TextEditor:
def __init__(self):
self.s = ''
self.cursor = 0
def addText(self, text: str) -> None:
s=self.s
cursor =self.cursor
self.s = s[:cursor] + text + s[cursor:]
self.cursor += len(text)
def deleteText(self, k: int) -> int:
s=self.s
cursor =self.cursor
right = s[cursor:]
k = min(k,cursor)
self.cursor -= k
left = s[:self.cursor]
self.s = left+right
return k
def cursorLeft(self, k: int) -> str:
s=self.s
cursor =self.cursor
k = min(k,cursor)
self.cursor -= k
return s[max(0,self.cursor-10):self.cursor]
def cursorRight(self, k: int) -> str:
s=self.s
cursor =self.cursor
k = min(k,len(s)-cursor)
self.cursor += k
return s[max(0,self.cursor-10):self.cursor]
# Your TextEditor object will be instantiated and called as such:
# obj = TextEditor()
# obj.addText(text)
# param_2 = obj.deleteText(k)
# param_3 = obj.cursorLeft(k)
# param_4 = obj.cursorRight(k)
栈
class TextEditor:
def __init__(self):
self.left = [] # 两个栈
self.right = []
def addText(self, text: str) -> None:
for c in text:
self.left.append(c)
def deleteText(self, k: int) -> int:
ans = 0
while self.left and k:
self.left.pop()
ans += 1
k -= 1
return ans
def cursorLeft(self, k: int) -> str:
while self.left and k:
self.right.append(self.left.pop())
k-= 1
if len(self.left) >= 10:
return ''.join(self.left[-10:])
else:
return ''.join(self.left)
def cursorRight(self, k: int) -> str:
while self.right and k:
self.left.append(self.right.pop())
k-=1
if len(self.left) >= 10:
return ''.join(self.left[-10:])
else:
return ''.join(self.left)