大数和中的极值位距离(模拟大数加法) | 豆包MarsCode AI刷题

130 阅读5分钟

一、问题背景

小R面对一个问题,她有两个由数字字符组成的超大字符串数,需要求出这两个数相加后得到的字符串数中的最大数和最小数之间的位数差距。如果结果中所有数字都相同,则差距为 0。如果存在多个符合最大或最小条件的数,应该选择最小的位置差。

例如,字符串数 "111" 和 "222" 相加得到 "333",所有数字相同,因此位数差为 0。另一例子,字符串数 "111" 和 "34" 相加得到 "145",其中最大数是 '5' 位于第 3 位,最小数是 '1' 位于第 1 位,他们之间的位差为 1。

总的来说,本题要求我们计算两个超大数字字符串相加后的结果中,最大数字最小数字的位置差。

二、 问题分析

给定两个数字字符串 string1string2,我们需要执行以下任务:

  1. 计算两个字符串代表的数字的和。由于这两个数字可能非常大,因此不能直接将它们转化为整数进行加法。我们需要模拟手动加法,从最低位开始逐位相加。
  2. 在加法结果中,找出最大数字和最小数字的位置。注意,如果存在多个相同的最大或最小数字,我们需要选择最小位置的差。
  3. 如果结果字符串中的所有数字相同,那么差距为 0

三、解决思路

  1. 模拟加法

    • 我们从字符串的最右端(最低位)开始,对每一位进行加法。加法过程中需要处理进位。
    • 对于两个数字字符串 string1 和 string2,从低位到高位依次进行逐位相加,直到两个字符串的所有数字都被处理完。如果还有进位,需要把进位添加到结果中。
  2. 查找最大和最小数字的位置差

    • 一旦得到相加后的结果字符串,我们遍历这个结果字符串,找出其中的最大和最小数字,并记录它们的位置。根据这些位置,计算出它们之间的差值。
  3. 返回位数差

    • 如果加法结果中所有数字相同,位差为 0。否则,返回最大数字和最小数字位置之间的差值。

四、代码实现

def solution(string1, string2):
    # Step 1: 手动加法
    str1_index = len(string1) - 1
    str2_index = len(string2) - 1
    carry = 0
    sb = []
    
    # 执行手动加法
    while str1_index >= 0 or str2_index >= 0:
        digit1 = ord(string1[str1_index]) - ord('0') if str1_index >= 0 else 0
        digit2 = ord(string2[str2_index]) - ord('0') if str2_index >= 0 else 0
        
        sum_val = digit1 + digit2 + carry
        carry = sum_val // 10  # 计算进位
        sb.append(str(sum_val % 10))  # 存储当前位的数字
        
        str1_index -= 1
        str2_index -= 1
    
    # 如果有进位,追加到结果中
    if carry > 0:
        sb.append(str(carry))
    
    # Step 2: 反转并生成结果字符串
    s = ''.join(reversed(sb))
    
    # Step 3: 找到最大和最小数字的位置差
    max_index = 0
    min_index = 0
    result = float('inf')
    
    for j in range(1, len(s)):
        # 更新最大和最小数字的位置
        if s[j] > s[max_index]:
            max_index = j
            result = abs(max_index - min_index) - 1
        elif s[j] < s[min_index]:
            min_index = j
            result = abs(max_index - min_index) - 1
        else:
            if s[j] == s[max_index]:
                max_index = j
            if s[j] == s[min_index]:
                min_index = j
            result = min(result, 0 if max_index == min_index else abs(max_index - min_index) - 1)
    
    return result

代码解释

  1. 模拟加法

    • 我们通过两个指针 str1_index 和 str2_index 来从字符串的末尾开始加法,每次处理一位数字。对于任意一位,若该位置有数字,则取数字,否则取 0。
    • 加法结果 sum_val 通过 sum_val = digit1 + digit2 + carry 得到,计算结果的当前位 sum_val % 10 添加到结果字符串,进位通过 carry = sum_val // 10 计算。
  2. 反转字符串

    • 由于加法从低位开始,所以结果是倒序的,因此需要使用 reversed(sb) 反转结果。
  3. 找最大和最小数字的位置差

    • 遍历结果字符串 s,找到最大和最小数字的第一个位置,然后计算它们之间的位差。如果所有数字相同,则返回 0。

五、复杂度分析

  • 时间复杂度

    • 手动加法的时间复杂度为 O(n),其中 n 是两个字符串长度之和。我们逐位加法直到两个字符串都被处理完。
    • 查找最大和最小数字的位置差需要遍历加法结果,时间复杂度为 O(m),其中 m 是加法结果的长度(通常是两个字符串长度之和)。

    因此,整个算法的时间复杂度为 O(n)。

  • 空间复杂度

    • 主要的空间消耗是存储加法结果字符串 s,其长度为加法结果的位数,即 O(n)。

六、总结

本题通过模拟手动加法的方式解决了超大数字的加法问题,并通过遍历加法结果字符串来计算最大和最小数字的位置差。

AI刷题让我深刻意识到算法学习和实践的高效性。传统上,解题往往需要大量的手动搜索、推敲和试错,而AI可以在几秒钟内给出完整的解答并解释思路。这种快速反馈让我能及时调整自己的解题方法,避免在某些误区上浪费过多的时间。当然,我也有一些反思。虽然AI提供了解题方案和思路,但如果仅仅依赖AI解题,可能会失去自己思考的机会。因此,我在使用AI刷题时,尽量将它作为一个辅助工具,在理解解题思路后,自己动手实现,进一步加深对算法的掌握。通过这种方式,AI成为了我学习的一部分,而不是代替我思考的工具。