Leetcode 984:不含 AAA 或 BBB 的字符串(超详细的解法!!!)

给定两个整数 AB,返回任意字符串 S,要求满足:

  • S 的长度为 A + B,且正好包含 A'a' 字母与 B'b' 字母;
  • 子串 'aaa' 没有出现在 S 中;
  • 子串 'bbb' 没有出现在 S 中。

示例 1:

输入:A = 1, B = 2
输出:"abb"
解释:"abb", "bab" 和 "bba" 都是正确答案。

示例 2:

输入:A = 4, B = 1
输出:"aabaa"

提示:

  1. 0 <= A <= 100
  2. 0 <= B <= 100
  3. 对于给定的 AB,保证存在满足要求的 S

解题思路

这个问题非常简单(其实这是一个数学问题),我们首先想到的解法是贪心算法。我们可以分成如下几种情况去判断

  • A = B A=B A=B
  • A &gt; B ​ A &gt; B​ A>B
  • A &lt; B A &lt; B A<B

第一种情况很简单,我们直接返回'ab'*A(或'ab'*B)即可。对于第二种和第三种情况,我们都按照第二种考虑,对于第三种情况我们交换A,B即可。接着我们判断当A or B不为空的时候,如果A>B的话,我们就添加aab,否则我们添加ab

class Solution:
    def strWithout3a3b(self, A, B, a='a', b='b'):
        """
        :type A: int
        :type B: int
        :rtype: str
        """
        if A == B:
            return (a+b)*B
        if B > A: 
            A, B = B, A
            a, b = b, a
        
        res = ''
        while A or B:
            if A: 
                res += a
                A -= 1
            if A > B:
                res += a
                A -= 1
            if B:
                res += b
                B -= 1
        
        return res

我们也可以继续优化这个问题,我们可以先计算dif=abs(A-B)。我们首先判断difB谁大?如果B更大的话,我们首先将'aab'*(A-B)添加到res中(因为此时aa的数量最多为A-B),然后再将'ab'*(B*2-A)添加到结果中,例如A=4,B=3,结果就是aababab。如果dif>B的话,我们首先将'aab'*B添加到res中(因为此时aa的数量最多为B,并且此时我们的b也用完了),然后再将'a'*(A-2*B)添加到结果中(题设中保证了我们一定会有结果,此时我们通过上面的策略一定是最优的,为什么?),例如A=4,B=1,结果就是aabaa

class Solution:
    def strWithout3a3b(self, A, B, a='a', b='b'):
        """
        :type A: int
        :type B: int
        :rtype: str
        """
        if A == B:
            return (a+b)*B
        
        if B > A: 
            A, B = B, A
            a, b = b, a
        if A >= B * 2: 
            return (a + a + b) * B + a * (A - B * 2)
        return (a + a + b) * (A - B) + (a + b) * (B * 2 - A)

这个问题使用递归的话,会更加简洁。递归的思路也非常简单,我们同样也只考虑三种情况,我们首先判断A>B,如果成立,我们返回a*2+b+f(A-2,B-1),如果A==B,我们返回(a+b)*A,如果A<B的话,我们返回f(B,A,b,a)(也就是交换A,B顺序)。接着考虑边界情况,也就是B==0的话,我们只要返回A*a即可。

class Solution:
    def strWithout3a3b(self, A, B, a='a', b='b'):
        """
        :type A: int
        :type B: int
        :rtype: str
        """
        if B > A: 
            return self.strWithout3a3b(B, A, b, a)
        if B == 0:
            return a*A
        if A > B:
            return (a*2+b)+self.strWithout3a3b(A-2, B-1, a, b)
        else:
            return (a+b)+self.strWithout3a3b(A-1, B-1, a, b)

reference:

https://leetcode.com/problems/string-without-aaa-or-bbb/discuss/226649/JavaC%2B%2B-(and-Python)-simple-greedy

我将该问题的其他语言版本添加到了我的GitHub Leetcode

如有问题,希望大家指出!!!

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
KMP算法是一种字符串匹配算法,用于在一个文本串S内查找一个模式串P的出现位置。它的时间复杂度为O(n+m),其中n为文本串的长度,m为模式串的长度。 KMP算法的核心思想是利用已知信息来避免不必要的字符比较。具体来说,它维护一个next数组,其中next[i]表示当第i个字符匹配失败时,下一次匹配应该从模式串的第next[i]个字符开始。 我们可以通过一个简单的例来理解KMP算法的思想。假设文本串为S="ababababca",模式串为P="abababca",我们想要在S中查找P的出现位置。 首先,我们可以将P的每个前缀和后缀进行比较,得到next数组: | i | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | | --- | - | - | - | - | - | - | - | - | | P | a | b | a | b | a | b | c | a | | next| 0 | 0 | 1 | 2 | 3 | 4 | 0 | 1 | 接下来,我们从S的第一个字符开始匹配P。当S的第七个字符和P的第七个字符匹配失败时,我们可以利用next[6]=4,将P向右移动4个字符,使得P的第五个字符与S的第七个字符对齐。此时,我们可以发现P的前五个字符和S的前五个字符已经匹配成功了。因此,我们可以继续从S的第六个字符开始匹配P。 当S的第十个字符和P的第八个字符匹配失败时,我们可以利用next[7]=1,将P向右移动一个字符,使得P的第一个字符和S的第十个字符对齐。此时,我们可以发现P的前一个字符和S的第十个字符已经匹配成功了。因此,我们可以继续从S的第十一个字符开始匹配P。 最终,我们可以发现P出现在S的第二个位置。 下面是KMP算法的C++代码实现:

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值