小D的 abc 变换问题 | 豆包MarsCode AI刷题

108 阅读4分钟

题目描述

Snipaste_2024-11-05_11-06-23.png

题目分析

每次操作都对每个字符同时进行如下变换:

  • 'a' -> 'bc'
  • 'b' -> 'ca'
  • 'c' -> 'ab'

初始字符串的每个字符在变换后都会“裂变”成一串新的字符,这些新字符又会在下次变换中进一步“分裂”。这个过程就像递归一样,不断增长,越来越大。

暴力解法——穷尽膨胀之路

想法

我们可以直接按照题意,模拟每次的裂变操作。对于每一轮的变换,我们生成一个新的字符串,通过将原字符串中的每个字符按规则替换成新的字符串段来更新它。这种方法直白易懂,但是随着操作次数增多,字符串的长度会以指数方式增长,计算量也会迅速飙升。

步骤

  1. 将字符串中的每个字符依次替换为对应的变换结果。
  2. 更新字符串,重复步骤1,共执行 次。

代码实现(python)


def solution(s: str, k: int) -> str:
    # 将字符串转换为列表
    s = list(s)
    
    # 进行 k 次变换
    for _ in range(k):
        # 初始化新的字符串列表
        new_s = []
        
        # 对当前字符串中的每个字符进行变换
        for char in s:
            if char == 'a':
                new_s.extend(['b', 'c'])
            elif char == 'b':
                new_s.extend(['c', 'a'])
            elif char == 'c':
                new_s.extend(['a', 'b'])
        
        # 更新字符串列表
        s = new_s
    
    # 将列表转换回字符串并返回
    return ''.join(s)

分析

这个方法在早期操作次数(即k较小)时还可以运行得动,但随着k增加,字符串长度会成倍暴涨,直接超出计算机的承受范围。这就像在给怪物喂养无限饲料一样,很快它就会变成无边无际的“字符海啸”——所以,暴力法很容易超时或耗尽内存。

当然,其实我暴力法提交上去直接过了,所以接下来的都不用看了

优化解法——解析递归结构,掌控裂变规律

既然暴力破解太恐怖,我们可以换个思路,通过分析找出变换的规律。我们的目标是从指数增长中找出规律,用一个“公式”直接计算出最后的结果,而不是一步步模拟。

发现规律

观察前几次变换的结果,我们可以看出一点规律性:

  1. 初始字符串 "abc"
  2. 第 1 次变换得到 "bccaab".
  3. 第 2 次变换得到 "caababbcbcca".

可以发现,这种“裂变”中包含了递归结构!经过 k 次变换的结果,其实可以看作是一个递归展开的结果。实际上,每个字符的变化模式会在每次操作中自我重复和膨胀。因此我们可以通过预计算变换后的字符串片段,而不必每次都重新生成整个字符串。

优化思路

我们可以通过动态规划或递归缓存每个字符的变换结果,在操作前先计算每个字符在 k 次变换后的结果,然后直接拼接这些结果!

def solution(s: str, k: int) -> str:
    # 递归缓存的字典,用于存储每个字符在 k 次变换后的结果
    memo = {}

    # 定义递归函数,用来计算字符经过 k 次变换后的结果
    def abc_transform_optimized(char: str, k: int) -> str:
        # 递归终止条件
        if k == 0:
            return char
        # 如果已经计算过,直接返回缓存的结果
        if (char, k) in memo:
            return memo[(char, k)]
        
        # 根据当前字符选择对应的变换,并递归求解
        if char == 'a':
            result = abc_transform_optimized('b', k - 1) + abc_transform_optimized('c', k - 1)
        elif char == 'b':
            result = abc_transform_optimized('c', k - 1) + abc_transform_optimized('a', k - 1)
        else:  # char == 'c'
            result = abc_transform_optimized('a', k - 1) + abc_transform_optimized('b', k - 1)
        
        # 缓存结果
        memo[(char, k)] = result
        return result

    # 计算初始字符串中每个字符经过 k 次变换后的结果并拼接
    transformed_result = ''.join(abc_transform_optimized(char, k) for char in s)
    return transformed_result

代码解释

  1. 递归缓存memo 是一个字典,用于缓存每个字符在 k 次变换后的结果,避免重复计算。
  2. 递归求解:通过递归调用,每次根据字符变换规则,将变换次数 k 递减直至 0(即不再变换)。
  3. 拼接结果:初始字符串的每个字符经过 k 次变换的结果,最终拼接成最后的字符串。

时间复杂度分析

这个优化方法极大减少了重复计算,通过记忆化缓存每个字符的变换结果,我们在大多数情况下可以避免指数增长。虽然最终结果依然会很大,但相比暴力法,我们只需计算少量的关键字符变换。