VP 周赛 第 389 场周赛
第三题3085. 成为 K 特殊字符串需要删除的最少字符数
双指针优化$O(n)$
第三题做出来了但做法不优并且错的次数太多了。
-
题目大意:给定一个字符串
word
和一个整数k,定义特殊字符串为满足|freq(word[i]) - freq(word[j])| <= k
对于字符串中所有下标i和j都成立的字符串。其中,freq(x)
表示字符x在word中的出现频率,|y|
表示y的绝对值。要求计算使word
成为k特殊字符串所需删除的字符的最小数量。 -
实现思路:首先统计
word
中每个字符的出现频率,然后对频率进行排序。接着遍历频率列表,从最大的频率开始,逐步减少频率,直到满足特殊字符串的条件。在减少频率的过程中,利用一个指针指向频率列表中的当前位置,不断向前移动,更新需要删除的字符数量。最终得到使word
成为k
特殊字符串所需删除的最小字符数量。
class Solution:
def minimumDeletions(self, word: str, k: int) -> int:
ans = 2e9
cnt = sorted(Counter(word).values())
numFre = len(cnt)-1
delCnt = len(word)
right = numFre
for cur in range(numFre, -1, -1):
delCnt-=cnt[cur]
maxFre = cnt[cur]+k
while right>cur and cnt[right]>maxFre:
delCnt+=cnt[right]
right-=1
ans = min(ans, delCnt-(numFre-right)*maxFre)
return ans
第四题3086. 拾起 K 个 1 需要的最少行动次数
题目大意:给定一个二进制数组nums
,长度为n,以及一个正整数k和非负整数maxChanges
。Alice在一个游戏中需要从nums
中拾起k个1,游戏开始时,Alice可以选择任意位置站立。Alice可以执行两种行动:一是将一个0改为1,次数不超过maxChanges
;二是交换相邻位置的1和0。返回Alice拾取k个1所需的最少行动次数。
实现思路:首先,统计nums
中1的位置,同时记录每个1的前缀和。然后确定最多可以拾取的1的个数,即为maxChanges
和当前1的个数的最小值。如果最大变化次数maxChanges
足够多,那么不需要交换1的位置,直接计算需要变化的次数即可;否则,利用二分搜索确定需要交换的1的位置,计算交换和变化的次数。最终返回行动次数。
class Solution:
def minimumMoves(self, nums: List[int], k: int, maxChanges: int) -> int:
pos = []
n=len(nums)
c=0
for i, v in enumerate(nums):
if not v:
continue
pos.append(i)
if c==3:
continue
c=max(c, 1)
if i>0 and nums[i]==nums[i-1]:
c = max(2, c)
if i>1 and nums[i]==nums[i-1] and nums[i]==nums[i-2]:
c = max(3, c)
c = min(c, k)
if maxChanges>=k-c:
return max(0, (k-c)*2)+max(0, c-1)
n = len(pos)
preSum = list(accumulate(pos, initial = 0))
ret = inf
rest = k-maxChanges
for right in range(rest, n+1):
left = right-rest
i=left+right>>1
s1 = pos[i]*(i-left) - (preSum[i]-preSum[left])
s2 = preSum[right]-preSum[i]-pos[i]*(right-i)
ret = min(ret, s1+s2)
return ret+maxChanges*2