双指针
最小替换子串长度
问题描述
小F得到了一个特殊的字符串,这个字符串只包含字符A、S、D、F,其长度总是4的倍数。他的任务是通过尽可能少的替换,使得A、S、D、F这四个字符在字符串中出现的频次相等。求出实现这一条件的最小子串长度。
测试样例
样例1:
输入:
input = "ADDF"
输出:1
样例2:
输入:
input = "ASAFASAFADDD"
输出:3
样例3:
输入:
input = "SSDDFFFFAAAS"
输出:1
样例4:
输入:
input = "AAAASSSSDDDDFFFF"
输出:0
样例5:
输入:
input = "AAAADDDDAAAASSSS"
输出:4
解题思路
我们需要在字符串中找到一个最小的子串,使得替换掉该子串的字符后,整个字符串中 A、S、D、F 的出现次数能够相等。由于字符串长度是 4 的倍数,我们可以计算出每个字符的理想出现次数,即 len(input) / 4。然后,我们使用滑动窗口来寻找最小的子串,满足替换该子串后各字符频次达到理想值。
算法步骤
- 初始化理想频次:
计算每个字符的理想频次ideal_count = len(input) // 4。 - 统计当前字符频次:
使用Counter统计字符串中A、S、D、F各字符的频次,得到current_counts。 - 计算需要调整的频次:
计算每个字符的超出理想频次的数量,即需要被替换的字符数,它表示在子串中至少需要包含多少个字符来进行替换,使整个字符串达到理想状态。 如果所有字符的值都为 0,说明字符串已经满足要求,直接返回0。 - 滑动窗口查找最小子串:
- 定义左右指针
left和right以及window_counts,用于记录当前窗口中各字符的频次。 - 从左到右扩展右指针
right,每加入一个字符,更新window_counts。 - 在窗口包含所需的替换字符数量时,开始收缩左指针
left,直到窗口不再满足条件。 - 在每次满足条件时,记录当前窗口的长度,并更新
min_length保存最小的子串长度。
- 定义左右指针
- 返回结果
代码
def solution(input):
# Please write your code here
ideal_count = len(input) // 4
# 统计当前频次
current_counts = {char: input.count(char) for char in 'ASDF'}
# 计算需要替换的字符数
needed_replacements = {char: max(0, current_counts[char] - ideal_count) for char in 'ASDF'}
# 如果不需要替换,直接返回0
if all(needed_replacements[char] == 0 for char in 'ASDF'):
return 0
# 滑动窗口初始化
left = 0
min_length = len(input)
window_counts = {char: 0 for char in 'ASDF'}
# 滑动窗口算法
for right in range(len(input)):
# 更新窗口内字符计数
window_counts[input[right]] += 1
# 检查窗口是否满足替换条件
while all(window_counts[char] >= needed_replacements[char] for char in 'ASDF'):
# 更新最小长度
min_length = min(min_length, right - left + 1)
# 移动左指针
window_counts[input[left]] -= 1
left += 1
return min_length
if __name__ == "__main__":
# You can add more test cases here
print(solution("ADDF") == 1 )
print(solution("ASAFASAFADDD") == 3)
字典序最小的01字符串
问题描述
小U拥有一个由0和1组成的字符串,她可以进行最多k次操作,每次操作可以交换相邻的两个字符。目标是通过这些操作,使得最终得到的字符串字典序最小。
例如,小U当前有一个字符串 01010,她最多可以进行 2 次相邻字符交换操作。通过这些操作,她可以将字符串调整为 00101,这是可以通过不超过2次操作得到的字典序最小的字符串。
现在,小U想知道,经过最多k次操作后,能够得到的字典序最小的字符串是什么。
测试样例
样例1:
输入:
n = 5, k = 2, s = "01010"
输出:'00101'
样例2:
输入:
n = 7, k = 3, s = "1101001"
输出:'0110101'
样例3:
输入:
n = 4, k = 1, s = "1001"
输出:'0101'
解题思路
解决该题目,我们可以使用贪心算法的思想。
目标是使字符串的字典序最小,因此每次操作时优先将字符 '0' 移动到最前面,尽可能地将字符 '1' 往后移即可
算法步骤
- 遍历字符串:找到每个
'0'并设法将它往前移动。 - 相邻交换:每次交换会消耗一次操作次数
k,直到操作次数耗尽。 - 贪心移动:每次总是尽可能将
'0'往前移,以便字典序更小。
代码
def solution(n: int, k: int, s: str) -> str:
# write code here
s = list(s) # 将字符串转换为列表以便进行交换操作
for i in range(n):
if s[i] == '0':
continue # 当前位置已经是0,不需要交换
# 找到当前位置之后最近的0
for j in range(i+1, n):
if s[j] == '0':
# 计算从j到i的交换次数
swaps = j - i
if swaps <= k:
# 进行交换
s[i], s[j] = s[j], s[i]
k -= swaps
break
return ''.join(s)
if __name__ == '__main__':
print(solution(5, 2, "01010") == '00101')
print(solution(7, 3, "1101001") == '0110101')
print(solution(4, 1, "1001") == '0101')