LeetCode:构造有效字符串的最少插入数

文章讲述了如何通过动态规划解决LeetCode题目,计算给定字符串word最少需要插入多少个abc字母使其有效,特别考虑了字符之间的字典序关系。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

地址:. - 力扣(LeetCode)
题目描述:给你一个字符串 word ,你可以向其中任何位置插入 “a”、“b” 或 “c” 任意次,返回使 word 有效 需要插入的最少字母数。
如果字符串可以由 “abc” 串联多次得到,则认为该字符串 有效

提示:

  • 1 <= word.length <= 50
  • word 仅由字母 “a”、“b” 和 “c” 组成。

题解

动态规划

d[i]表示前i个字符拼凑成若干个 abc所需要的最小插入数
d[0] = 0
如果word[i] 单独存在于一组 abc中,d[i]=d[i−1]+2
那怎么知道word[i]是不是单独存在一组abc中呢?

首先 我们能知道的是c>b>a
如果word[i]>word[i−1] 那就能肯定是在同一组abc中的
比如字符串ab,b>a 我们能肯定它们是在同一组abc中的
比如字符串ac,c>a 我们能肯定它们是在同一组abc中的
比如字符串bc,c>b 我们能肯定它们是在同一组abc中的

除了上述情况之外,其他的情况word[i]都是单独成一组的
比如ca,a<c,我们能肯定a就是单独成一组的,不可能跟前面的c成一组,因为这违背了abc这样的顺序
既然是单独成一组,就需要再插入两个元素构成一组 所以d[i]=d[i−1]+2

如果 word[i]>word[i−1],那么 word[i]可以和 word[i−1] 在同一组 abc 中,d[i]=d[i−1]−1
这种情况就是word[i]跟前面可以成一组,但是我们要知道的是在word[i]插入进word[0]-word[i-1]之前,我们通过动态规划,已经计算好了word[0]-word[i-1]这个字符串拼凑成若干个 abc所需要的最小插入数
那就是可以理解为,这个时候,word[0]-word[i-1]的最后三位字符串已经成组成abc了
这个时候我们把word[i]添加进去成组,也就意味着d[i-1],也就是word[0]-word[i-1]这个字符串拼凑成若干个 abc所需要的最小插入数需要减1,因为word[i]替换占位了,相应的插入数就要减少了,所以d[i]=d[i−1]−1

通过一个例子加深理解:
word=aacabc
答案应该是:3 a(bc)a(b)cabc

第一步:求d[1],因为a前面是空字符,所以字符串a肯定是自成一组的,d[1] = d[0]+2 = 2

第二步:求d[2],因为a前面是a,所以字符串word[1]:a自成一组的,d[2] = d[1]+2 = 4

第三步:求d[3],因为c前面是a,所以字符串word[2]:c跟前面的word[1]:a是同一组的,d[3] = d[2]-1 = 3

第四步:求d[4],因为a前面是c,所以字符串word[3]:a自成一组,d[4] = d[3]+2 = 5

第五步:求d[5],因为b前面是a,所以字符串word[4]:b跟前面的word[3]:a是同一组的,d[5] = d[4]-1 = 4

第六步:求d[6],因为c前面是b,所以字符串word[5]:c跟前面的word[4]:b是同一组的,d[6] = d[5]-1 = 3

所以答案就是d[6] = 3

代码实现
/**
 * @param {string} word
 * @return {number}
 */
var addMinimum = function(word) {
   const n = word.length
   const d = new Array(n+1).fill(0)
   for(let i=1;i<=n;i++){
       d[i] = d[i-1]+2
       if(i>1&&word[i-1]>word[i-2]){
            d[i] = d[i-1]-1
       }
   }
   
   return d[n]
};

状态转移时,最多只会依赖前一个状态 d[i−1],因此使用滚动数组优化可以使得空间复杂度降至 O(1)

/**
 * @param {string} word
 * @return {number}
 */
var addMinimum = function(word) {
   const n = word.length
   let d = 0
   for(let i=1;i<=n;i++){
       d+=2
       if(i>1&&word[i-1]>word[i-2]){

           // d = (d-2)-1  d-2是为了还原状态 因为前面+2了
           d-=3
       }
   }
   
   return d
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值