今天是第一次写文章,在编程,算法方面我确实算个菜鸡,毕竟大学才开始接触编程,也不是计算机科班出身,作为一个初学者也只能分享一下自己的成长经历吧哈哈
今天决定午饭后到晚饭前刷题,晚饭后散个步再去学习AI课程。哎感觉时间好不够用,早上的时间也应该抽出来学习的,希望能完成字节的项目吧。
到目前为止今天才写出来一道题,好慢。下面看题吧:
最小替换子串长度
问题描述
小F得到了一个特殊的字符串,这个字符串只包含字符A、S、D、F,其长度总是4的倍数。他的任务是通过尽可能少的替换,使得A、S、D、F这四个字符在字符串中出现的频次相等。求出实现这一条件的最小子串长度。
思路解析
这个题我一打眼还以为是最小替换字符次数,还觉得有点太简单了。但其实要求的是最小替换字串的长度,就是说我们需要修改该串的某个子串,让四个字符出现次数相同,求可能的最小子串。 我的解题思路比较暴力,具体而言分为两个步骤:
1.记录每个字符出现的次数,由此求出需要修改的字符数量。最终目标是让每个字符出现len(s)//4次,所以我们只需要关注出现次数大于这个数的字符(下文称他们为 多余字符 )就行。在数据结构方面,我选择了字典。因为多余字符的数量不确定,有可能是1,2,3个,所以使用字典比较方便。
2.知道了多余字符以及他们多余的数量,例如多了3个'A',2个'F',我们的目标就相当于找到字符串的包含 3个'A',2个'F' 的最小子串。这里我的思路是滑动窗口(或者说双指针)。具体而言:
- 初始化两个指针 `ll` 和 `rr`,均指向字符串的起始位置。
- 不断增加 `rr`,扩展窗口的右边界,直到窗口内包含足够的多余字符。
- 一旦窗口内包含了所需的多余字符,我们开始尝试增大 `ll`,即收缩窗口的左边界,以尽量缩小窗口的大小,直到不能再缩小为止。
- 记录当前窗口的长度,作为可能的最小字串长度。
- 将 `ll` 向右移动一位,继续上述步骤,直到遍历完整个字符串。
- 最后,返回记录的最小窗口长度。
通过这种方法,我们可以高效地找到包含所需多余字符的最小子串,从而确定需要修改的最短子串长度
最后,贴上我的代码,语言为Python:
def ge(dic1:dict,dic2:dict):
# 这个函数用于比较dic1中的每个键值都大于等于dic2
try:
for key in dic1:
if dic1[key]>=dic2[key]:
continue
break
else:
return True
return False
except KeyError:
return False
def solution(input):
# 统计每个字符的出现次数
ca = cs = cd = cf = 0
for i in input:
if i == 'A':
ca += 1
elif i == 'S':
cs += 1
elif i == 'D':
cd += 1
else:
cf += 1
# 如果所有字符出现次数已经相等,直接返回0
if ca == cs == cd == cf:
return 0
n = len(input)
st = n // 4
need = {'A': max(0, ca - st), 'S': max(0, cs - st), 'D': max(0, cd - st), 'F': max(0, cf - st)} # need为字串实际需要的字符以及数量
conter = {item:0 for item in need if need[item] > 0} # 记录窗口内目前有的字符数量
ll = rr = 0 # 窗口边界
ans = float('inf')
while rr < n:
# 扩大窗口
for key in conter:
if input[rr]==key:
conter[key] += 1
# 检查是否满足条件
while ge(conter,need):
# 更新答案
ans = min(ans, rr - ll + 1)
# 收缩窗口
if input[ll] in conter:
conter[input[ll]]-=1
ll+=1
rr += 1
return ans if ans != float('inf') else 0
if __name__ == "__main__":
print( solution("ADDF") == 1 )
print( solution("ASAFASAFADDD") == 3 )