周赛240407
出师不利,第一题变量名能写错,慢就是快,少就是多,提交之前一定要有万全的检查。
第二题100242. 满足距离约束且字典序最小的字符串
纯思维题,先花时间想清楚基础问题再想后面的问题。吸取教训,代码一定要写的清晰明了,自己才能更好的看懂并写下去。
Python 取模运算中余数符号和除数符号一致,并满足:$被除数-除数*商(整除)=余数$
思路:转换问题,问不超过k,那么用完$k$是最优的,因为用$k$总能使字典序变小(除非原序列全是$a$), 那么就依次枚举,知道不能转换为$a$的情况下将剩余的$k$转换称可以转换成的最小的字典序字母。
class Solution:
def getSmallestString(self, s: str, k: int) -> str:
s = list(s)
n = len(s)
for i in range(n):
d = min(ord(s[i])-ord('a'), ord('a')-ord(s[i])+26)
if k>=d:
k-=d
s[i]='a'
else:
num = ord(s[i])-ord('a')
ch = min((num-k)%26, (num+k)%26)
ch = chr(ch+ord('a'))
s[i] = ch
break
return ''.join(s)
第三题 3107. 使数组中位数等于 K 的最少操作数
这题比较简答,最后一刻用二分交的,结果右端点取值保守错了一发。
实际不需要二分,在排好序的序列里,用中位数去靠近中位数更优,所以直接排序计算将前面比k大的和后面比$k$小的计算差值就可以了。
class Solution:
def minOperationsToMakeMedianK(self, nums: List[int], k: int) -> int:
nums.sort()
n = len(nums)
mid = n // 2
op=abs(nums[mid]-k)
for i in range(mid):
if nums[i]>k:
op += nums[i] - k
for i in range(mid+1, n):
if nums[i]<k:
op += k - nums[i]
return op
第四题100244. 带权图里旅途的最小代价
并查集+思维题。如果一些数字相与$(and)$, 如果存在较小的数字二进制位中是$0$,那么就算有再多的数字在这一位上是$1$也没有用了。所以在一个连通块内最小代价就是所有边都走一遍,而连通块可以用并查集来判断。
class Solution:
def minimumCost(self, n: int, edges: List[List[int]], query: List[List[int]]) -> List[int]:
def find(x):
if p[x]!=x:
p[x]=find(p[x])
return p[x]
p={i:i for i in range(n)}
dis={}
ret=[]
for u,v,_ in edges:
p[find(u)]=find(v)
for u,v,w in edges:
pu = find(u)
if pu not in dis:
dis[pu]=w
else:
dis[pu]&=w
for x,y in query:
if x==y:
ret.append(0)
continue #如果相等一定要continue
px, py = find(x), find(y)
if px==py:
ret.append(dis[px])
else:
ret.append(-1)
return ret