解决leetcode第3816题.删除重复字符后的字典序最小字符串

3816.删除重复字符后的字典序最小字符串

难度:困难

问题描述:

给你一个字符串s,它由小写英文字母组成。

你可以进行如下操作任意次(可能为零次):

选择当前字符串s中至少出现两次的任意一个字母并删除其中的一次出现。

返回可以通过这种方式形成的字典序最小的结果字符串。

如果字符串a的某个位置与字符串b不同,且a在该位置的字母比b对应位置的字母在字母表中更靠前,则a被认为是字典序更小的字符串。如果a的前min(a.length,b.length)个字符都与b相同,则较短的字符串字典序更小。

示例1:

输入:s="aaccb"

输出:"aacb"

解释:

可以形成字符串"acb"、"aacb"、"accb"和"aaccb"。其中"aacb"是字典序最小的。

例如,可以选择字母'c'并删除它的第一次出现,得到"aacb"。

示例2:

输入:s="z"

输出:"z"

解释:

无法进行任何操作。只能形成字符串"z"。

提示:

1<=s.length<=105

s仅包含小写英文字母。

问题分析:

处理该问题经历了以下步骤

1先将字符串s中字符重复次数不小于2的字符找出,并将各个字母在字符串中出现的位置以列表形式给出,这些位置都是可能删除的位置。比如对于字符串aabbc,字符a和b重复次数不小于2次,字符a出现的位置为[0,1],字符b出现的位置为[2,3]。把不删除的情况也考虑进去,用-1表示不删除,则上面的列表依次变为[-1,0,1]和[-1,2,3]

2 把不同字母出现的索引号位置转换成跟字符串s等长的二进制字符串,如果不删除则字符串中不出现1,比如a出现的位置为['00000','10000','01000'],b出现的位置为['00000','00100','00010']。如果原字符串s中没有重复的字符,则生成与原字符串等长的全是0的二进制字符串

3 重复的字符只删除一次出现,所以要把删除的位置进行排列组合,就会出现下面的情况:['00000','00100','00010','10000','10100','10010','01000','01100','01010'],这种排列组合可以通过二进制或操作实现

4 上面的二进制排列实际上相当于是对原字符串进行处理的蒙板,对原字符串按蒙板进行操作,删除蒙板中1位置对应字符,保留0位置对应的字符,即是进行删除操作之后形成的字符串,如果其中有重复,去掉重复项,再进行字典升序排序,那么其中的第一个字符串即是字典序最小的

程序如下:

python 复制代码
#在字符串a中找到所有字符出现的次数,将次数不少于2次的字符保留,并形成元素为[字符,次数]的列表返回
def get_more_than_two_times_char_list(a):
    a=list(a)
    b=set(a)
    t=[]
    for i in b:
        t.append([i,a.count(i)])
    d=list(i for i in t if i[1]>=2)
    d.sort(key=lambda x: x[0])
    return d

#根据字符个数不小于2次的列表,生成每个字符出现的索引号列表并返回
def get_more_than_two_times_char_index_list(a,s):
    b=[]
    for i in a:
        c=[-1] #-1表示不去掉该字符的任何一个索引号
        k=0
        for j in range(i[1]):
            n=s.index(i[0],k)
            c.append(n)
            k=n+1
        b.append(c)
    return b
#根据索引号列表中的数据,将对应索引号位置以二进制的形式置为1
def create_binary_list(nums,n):
    b='0'*n
    c=[]
    for i in nums:
        if i==-1:
            c.append(b)
        else:
            left = b[:i]
            right = b[i + 1:]
            c.append(left + '1' + right)
    return c

#将两种字符出现的索引号二进制数进行或运算,获得组合之后的排列并返回
def get_combination_index(a,b,n):
    t=[]
    for i in a:
        for j in b:
            xi=int(i,2)
            xj=int(j,2)
            k=xi|xj
            x=bin(k)[2:]
            len_x=len(x)
            x=(n-len_x)*'0'+x
            t.append(x)
    return t

#生成字符个数不少于2的所有字符索引排列并返回
def get_all_combination_index(s):
    n=len(s)
    a=get_more_than_two_times_char_list(s)
    if not a:
        return [n*'0']
    b=get_more_than_two_times_char_index_list(a,s)
    c=create_binary_list(b[0],n)
    m=len(b)
    for i in range(1,m):
        d=create_binary_list(b[i],n)
        c=get_combination_index(c,d,n)
    return c

#将二进制形式的字符串解析为原字符串
def get_mask_str(s,mask):
    n=len(s)
    s=list(s)
    mask=list(mask)
    s_mask=zip(s,mask)
    s_mask=list(k[0] for k in s_mask if k[1]=='0')
    return ''.join(s_mask)

 #主程序
s=input('pls input s=')
c = get_all_combination_index(s)
t = []
for i in c:
    b = get_mask_str(s, i)
    t.append(b)
t = list(set(t))
t.sort()
if len(t)==1:
    print(f'无法进行任何操作。只能形成字符串{t[0]}')
else:
    print(f'可以形成的字符串有{t},其中{t[0]}是字典序最小的')

运行实例一

pls input s=ab

无法进行任何操作。只能形成字符串ab

运行实例二

pls input s=aabacb

可以形成的字符串有['aaacb', 'aabac', 'aabacb', 'aabc', 'aabcb', 'aacb', 'abac', 'abacb'],其中aaacb是字典序最小的

运行实例三

pls input s=aaab

可以形成的字符串有['aaab', 'aab'],其中aaab是字典序最小的

相关推荐
iAkuya1 小时前
(leetcode)力扣100 47从前序与中序遍历序列构造二叉树(迭代,递归)
算法·leetcode·职场和发展
七夜zippoe1 小时前
Python多线程性能优化实战:突破GIL限制的高性能并发编程指南
python·macos·多线程·读写锁·gil·rcu
chao_7892 小时前
链表题解——相交链表【Leetcode】(最新版,核心思路)
数据结构·python·leetcode·链表
十八岁讨厌编程2 小时前
【算法训练营 · 二刷总结篇】 数组与字符串部分
算法
tqs_123452 小时前
接口的路由和负载均衡
java·python
skywalk81632 小时前
介绍一下QuantConnect Lean(python 15k star)
开发语言·python·量化
lcz-20002 小时前
Silero-VAD模型自定义微调
python·音视频·vad·silero
玖日大大2 小时前
随机森林算法原理及实战代码解析
算法·随机森林·机器学习
CCPC不拿奖不改名2 小时前
Git 核心操作命令
人工智能·git·python·rnn·自然语言处理·josn