leetcode第161场周赛总结
第一题:5247. 交换字符使得字符串相同
有两个长度相同的字符串 s1 和 s2,且它们其中 只含有 字符 “x” 和 “y”,你需要通过「交换字符」的方式使这两个字符串相同。
每次「交换字符」的时候,你都可以在两个字符串中各选一个字符进行交换。
交换只能发生在两个不同的字符串之间,绝对不能发生在同一个字符串内部。也就是说,我们可以交换 s1[i] 和 s2[j],但不能交换 s1[i] 和 s1[j]。
最后,请你返回使 s1 和 s2 相同的最小交换次数,如果没有方法能够使得这两个字符串相同,则返回 -1 。
示例1:
输入:s1 = “xx”, s2 = “yy”
输出:1
解释:
交换 s1[0] 和 s2[1],得到 s1 = “yx”,s2 = “yx”。
示例2:
输入:s1 = “xy”, s2 = “yx”
输出:2
解释:
交换 s1[0] 和 s2[0],得到 s1 = “yy”,s2 = “xx” 。
交换 s1[0] 和 s2[1],得到 s1 = “xy”,s2 = “xy” 。
注意,你不能交换 s1[0] 和 s1[1] 使得 s1 变成 “yx”,因为我们只能交换属于两个不同字符串的字符。
示例3:
输入:s1 = “xx”, s2 = “xy”
输出:-1
实例4:
输入:s1 = “xxyyxyxyxx”, s2 = “xyyxyxxxyx”
输出:4
提示:
1 <= s1.length, s2.length <= 1000
s1, s2 只包含 ‘x’ 或 ‘y’。
分析:
1、首先考虑哪种情况是如何交换都不可能使两个字符串相等的,只有这两个字符串中所有x和y的个数加起来都是偶数才能通过交换使两个字符串相等,否则无论如何交换都不可能使两个字符串相等。
2、对于两个字符串中相同位置的字符,如果已经相等了的话,则可以不用考虑它们,我们只需考虑那些同样位置不相等的字符。同样位置字符不相等一共只有两种可能,一是s1中这个字符是x,s2中这个字符是y,二是s1中这个字符是y,s2中这个字符是x。我们考虑这种情况,s1[i]=‘x’,s1[j]=‘x’,s2[i]=‘y’,s2[j]=‘y’,这种情况类似于示例1,只需通过一次交换即可使s1和s2的i,j位置的字符都相同。同理,对于s1[i]=‘y’,s1[j]=‘y’,s2[i]=‘x’,s2[j]='x’这种情况也是只需一次交换即可。考虑另一种情况,即s1[i]=‘x’,s1[j]=‘y’,s2[i]=‘y’,s2[j]=‘x’,这种情况类似于示例2,需要通过两次交换才能使s1和s2的i,j位置的字符都相同。同理,对于s1[i]=‘y’,s1[j]=‘x’,s2[i]=‘x’,s2[j]='y’这种情况也是需要两次交换。所以,我们只需统计需要交换一次和需要交换两次的这些情况各有多少种,即可算出答案。
代码如下:
class Solution:
def minimumSwap(self, s1: str, s2: str) -> int:
dic1 = collections.Counter(s1)
dic2 = collections.Counter(s2)
ans = 0
if (dic1['x'] + dic2['x']) % 2 == 0 and (dic1['y'] + dic2['y']) % 2 == 0:
dic = collections.defaultdict(int)
for i in range(len(s1)):
if s1[i] == s2[i]:
continue
else:
dic[(s1[i], s2[i])] += 1
if dic[('x', 'y')]:
ans += dic[('x', 'y')] // 2
dic[('x', 'y')] %= 2
if dic[('y', 'x')]:
ans += dic[('y', 'x')] // 2
dic[('y', 'x')] %= 2
if dic[('y', 'x')]:
ans += dic[('y', 'x')] * 2
return ans
else:
return -1
第二题:5248. 统计「优美子数组」
给你一个整数数组 nums 和一个整数 k。
如果某个子数组中恰好有 k 个奇数数字,我们就认为这个子数组是「优美子数组」。
请返回这个数组中「优美子数组」的数目。
示例1:
输入:nums = [1,1,2,1,1], k = 3
输出:2
解释:包含 3 个奇数的子数组是 [1,1,2,1] 和 [1,2,1,1] 。
示例2:
输入:nums = [2,4,6], k = 1
输出:0
解释:数列中不包含任何奇数,所以不存在优美子数组。
示例3:
输入:nums = [2,2,2,1,2,2,1,2,2,2], k = 2
输出:16
提示:
1 <= nums.length <= 50000
1 <= nums[i] <= 10^5
1 <= k <= nums.length
分析:
这题我一开始的想法是用滑动窗口去做,但是写起来发现,好多情况是不适合用滑动窗口去考虑的,比如我现在的窗口内已经包含了k哥奇数了,这个时候如果窗口右边界之后还有偶数的话,右边界可以继续向后滑动,而如果这时候窗口左边界之后也有偶数的话,那窗口的左边界也可以继续向后滑动。这种情况下,窗口左右边界可以同时滑动,那么就不太好统计优美子数组的个数了。所以,受此启发,我想到了可以去找出数组中所有奇数的位置,然后考虑以每个奇数作为优美子数组中的第一个奇数,这样也就能根据k确定优美子数组中的最后一个奇数是谁,然后包含这k个奇数的优美子数组的个数就=(这个优美子数组的第一个奇数的下标-它前一个奇数的下标)×(这个优美子数组的最后一个奇数的下标-它后一个奇数的下标)。
代码如下:
class Solution:
def numberOfSubarrays(self, nums: List[int], k: int) -> int:
ans = 0
cnt = 0
mem = [-1]
for i, num in enumerate(nums):
if num % 2 == 1:
cnt += 1
mem.append(i)
mem.append(len(nums))
for i in range(1, len(mem)-k):
ans += (mem[i] - mem[i-1]) * (mem[i+k] - mem[i+k-1])
return ans
第三题:5249. 移除无效的括号
给你一个由 ‘(’、’)’ 和小写字母组成的字符串 s。
你需要从字符串中删除最少数目的 ‘(’ 或者 ‘)’ (可以删除任意位置的括号),使得剩下的「括号字符串」有效。
请返回任意一个合法字符串。
有效「括号字符串」应当符合以下 任意一条 要求:
空字符串或只包含小写字母的字符串
可以被写作 AB(A 连接 B)的字符串,其中 A 和 B 都是有效「括号字符串」
可以被写作 (A) 的字符串,其中 A 是一个有效的「括号字符串」
示例1:
输入:s = “lee(t©o)de)”
输出:“lee(t©o)de”
解释:“lee(t(co)de)” , “lee(t©ode)” 也是一个可行答案。
示例2:
输入:s = “a)b©d”
输出:“ab©d”
示例3:
输入:s = “))((”
输出:""
解释:空字符串也是有效的
示例4:
输入:s = “(a(b©d)”
输出:“a(b©d)”
提示:
1 <= s.length <= 10^5
s[i] 可能是 ‘(’、’)’ 或英文小写字母
分析:
使用栈来找出不匹配的括号。
代码如下:
class Solution:
def minRemoveToMakeValid(self, s: str) -> str:
mem = [0] * len(s)
stack = []
ans = ""
for i, c in enumerate(s):
if c not in ['(', ')']:
mem[i] = 1
else:
if c == '(':
stack.append([c, i])
else:
if not stack:
continue
else:
mem[stack[-1][1]] = 1
mem[i] = 1
stack.pop()
for i in range(len(mem)):
if mem[i] == 1:
ans += s[i]
return ans
第四题:5250. 检查「好数组」
给你一个正整数数组 nums,你需要从中任选一些子集,然后将子集中每一个数乘以一个 任意整数,并求出他们的和。
假如该和结果为 1,那么原数组就是一个「好数组」,则返回 True;否则请返回 False。
示例1:
输入:nums = [12,5,7,23]
输出:true
解释:挑选数字 5 和 7。
53 + 7(-2) = 1
示例2:
输入:nums = [29,6,10]
输出:true
解释:挑选数字 29, 6 和 10。
291 + 6(-3) + 10*(-1) = 1
示例3:
输入:nums = [3,6]
输出:false
提示:
1 <= nums.length <= 10^5
1 <= nums[i] <= 10^9
分析:
题目说可以任选一些子集,然后然后将子集中每一个数乘以一个 任意整数,并求出他们的和,假如该和结果为 1,那么原数组就是一个「好数组」。那么假设我挑两个数x和y,选择他们要×的参数为a和b,计算他们的和即(ax+by),现在假如x和y的最大公约数为1,那么(ax+by)可以写成1×(ax+by),只需要选择合适的a和b使ax+by=1即可。而如果x和y的最大公约数为1不为1,就假设为2吧,那么(ax+by)可以写成2×(ax’+by’),因为x和y都是正整数,而a,b是任意整数,所以(ax’+by’)的结果肯定是个整数,所以2×(ax’+by’)肯定是2的倍数,就不可能是1。所以只要能找出最大公约数是1的子集就能满足条件,否则就不能。
代码如下:
class Solution:
def isGoodArray(self, nums: List[int]) -> bool:
g = nums[0]
if len(nums) == 1 and g == 1:
return True
for num in nums[1:]:
g = math.gcd(num, g)
if g == 1:
return True
return False