3441.变成好标题的最少代价
难度:困难
问题描述:
给你一个长度为n的字符串caption。如果字符串中每一个字符都位于连续出现至少3次的组中,那么我们称这个字符串是好标题。
比方说:
"aaabbb"和"aaaaccc"都是好标题。
"aabbb"和"ccccd"都不是好标题。
你可以对字符串执行以下操作任意次:
选择一个下标i(其中0<=i<n)然后将该下标处的字符变为:
该字符在字母表中前一个字母(前提是caption[i]!='a')
该字符在字母表中后一个字母(caption[i]!='z')
你的任务是用最少操作次数将caption变为好标题。如果存在多种好标题,请返回它们中字典序最小的一个。如果无法得到好标题,请你返回一个空字符串""。
在字符串a和b中,如果两个字符串第一个不同的字符处,字符串a的字母比b的字母在字母表里出现的顺序更早,那么我们称字符串a的字典序比b小。如果两个字符串前min(a.length,b.length)个字符都相同,那么较短的一个字符串字典序比另一个字符串小。
示例1:
输入:caption="cdcd"
输出:"cccc"
解释:
无法用少于2个操作将字符串变为好标题。2次操作得到好标题的方案包括:
"dddd":将caption[0]和caption[2]变为它们后一个字符'd'。
"cccc":将caption[1]和caption[3]变为它们前一个字符'c'。
由于"cccc"字典序比"dddd"小,所以返回"cccc"。
示例2:
输入:caption="aca"
输出:"aaa"
解释:
无法用少于2个操作将字符串变为好标题。2次操作得到好标题的方案包括:
操作1:将caption[1]变为'b',caption="aba"。
操作2:将caption[1]变为'a',caption="aaa"。
所以返回"aaa"。
示例3:
输入:caption="bc"
输出:""
解释:
由于字符串的长度小于3,无法将字符串变为好标题。
提示:
1<=caption.length<=5*104
caption只包含小写英文字母。
问题分析:
我的思考是如果能够将caption分解为各种连续的子字符串,且每一个子字符串的长度至少为3个字符,把这种caption由不同子字符串的组合找出,问题就好办了。剩下的就是将子字符串中出现频率最高的字符找出,然后将其它非高频字符转换为高频字符,统计这种转换的步数,然后看哪一种子字符串组合转换为好标题的步数最少,这就是我们要找的解。
为此设计了几个函数:
- 函数turn_s2t(s,t),返回将一个字符s变为目标字符t经过的步数
- 函数get_steps(s),统计字符串s中频次最高的字母,并计算将其它字母变成这个最高频字母所要经过的步数,返回变换经过的步数和转变成的好标题字符串
- 函数decord(s,k),将一个字符串s分解为子字符串,返回所有的组合,一个长度为n的字符串,分解为至少包含3个字符的子字符串,最多可以有n//3个子字符串
- 函数get_min_steps(caption),返回各种由caption生成的子字符串组合转换成好标题所经过的步数和最终形成的好标题字符串,并按步数为第一关键字和字典序为第二关键字排序
- 最后我们直接提取返回结果,根据结果判断最少经过多少步转换成什么样的好标题,如果原caption字符数少于3个,则输出“标题字符数少于3个,无法经过操作转换成好标题!”
在整个编写中,感觉将一个caption分解为各种连续的字符数至少为3个及以上的子字符串的组合,难度比较大,经过反复实验,最终写成,后来自己撇开原来写好的代码,试着重写一遍,居然难以写出。
程序如下:
#将一个字符s变为目标字符t经过的步数,返回变化经过的步数
def turn_s2t(s,t):
s=ord(s)
t=ord(t)
if s<t:
return t-s
else:
return s-t
#统计字符串中频次最高的字母,并计算将其它字母变成这个最高频次字母所要经过的步数
# 并返回步数和转变成的字符串
def get_steps(s):
a=list(set(s))
# a.sort(key=lambda x:x[0])
b=[]
for i in a:
b.append([i,s.count(i)])
b.sort(key=lambda x:(-x[1],x[0]))
# print(b)
setps=0
t=b[0][0]
for i in s:
if i!=t:
c=turn_s2t(i,t)
setps=setps+c
return [setps,t*len(s)]
#将一个字符串分解为两个子字符串,返回所有的组合,一个长度为n的字符串
#最多可以分解为n//3组子字符串
def decord(s,k):
n=len(s)
a=[]
if n<3:
return ['']
elif n<6:
return [s]
else:
if k==2:
for i in range(3, n - 2):
left = s[:i]
right = s[i:]
a.append(left+'-'+ right)
return a
else:
for i in range(3,n-2):
left=s[:i]
right=decord(s[i:],k-1)
for j in right:
a.append(left+'-'+j)
return a
#将各种子字符串组合转换为好标题所经过的最少步数及最终转换成的好标题以列表形式返回
def get_min_steps(caption):
if len(caption)<3:
return [[0,'']]
j = decord(caption, len(caption) // 3)
if len(caption) >= 6:
j.append(caption)
j.sort()
print(f'由{caption}分解成的字符数至少为3个的子字符串为:{j}')
a=[]
for i in j:
if '-' not in i:
step,s=get_steps(i)
a.append([step,s])
else:
s_sub=i.split('-')
step=0
s_cap=''
for k in s_sub:
m,n=get_steps(k)
step=step+m
s_cap=s_cap+n
a.append([step,s_cap])
return a
#主程序
caption=input('pls input caption=')
s=get_min_steps(caption)
if s[0][1]=='':
print('标题字符数少于3个,无法经过操作转换成好标题!')
else:
s.sort(key=lambda x: (x[0], x[1]))
print(f'经过处理之后各种情况的操作步数及最终字符串:{s}')
print(f'经过{s[0][0]}次操作,变为{s[0][1]}字符串')
运行实例一:
pls input caption=abc
由abc分解成的字符数至少为3个的子字符串为:['abc']
经过处理之后各种情况的操作步数及最终字符串:[[3, 'aaa']]
经过3次操作,变为aaa字符串
运行实例二:
pls input caption=aacbbd
由aacbbd分解成的字符数至少为3个的子字符串为:['aac-bbd', 'aacbbd']
经过处理之后各种情况的操作步数及最终字符串:[[4, 'aaabbb'], [7, 'aaaaaa']]
经过4次操作,变为aaabbb字符串
运行实例三:
pls input caption=aaabbbcccd
由aaabbbcccd分解成的字符数至少为3个的子字符串为:['aaa-bbb-cccd', 'aaa-bbbc-ccd', 'aaab-bbc-ccd', 'aaabb-bcccd', 'aaabbb-cccd', 'aaabbbc-ccd', 'aaabbbcccd']
经过处理之后各种情况的操作步数及最终字符串:[[1, 'aaabbbcccc'], [2, 'aaabbbbccc'], [3, 'aaaabbbccc'], [4, 'aaaaaacccc'], [4, 'aaaaaccccc'], [6, 'aaaaaaaccc'], [12, 'aaaaaaaaaa']]
经过1次操作,变为aaabbbcccc字符串
运行实例四:
pls input caption=ab
标题字符数少于3个,无法经过操作转换成好标题!
感悟:
在编写函数返回数据时,一定要注意各种情况下返回数据类型格式的一致性!否则很容易出错。特别是在返回列表的数据类型时更要注意。