青训营X豆包MarsCode 技术训练营伴学笔记5 | 豆包MarsCode AI 刷题

62 阅读5分钟

大数和中的极值位距离

问题描述

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

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

问题知识点分析

大数加法 :大数加法是经典的字符串处理问题。给定两个超大的数字,需要逐位相加并处理进位,最终得到一个结果。

极值位距离: 对于加法结果字符串中的每个字符,需要找出最大和最小的数字,然后计算它们第一次出现的位置差;如果所有字符都相同,则位差为0;如果存在多个最大或最小数字,需要选择它们之间最小的位置差。

解题思路

可以将题目拆解成以下步骤:

  1. 首先,将两个字符串形式的数字相加。由于加法涉及到进位,从右往左逐位进行加法,并处理每一位上的进位。
  2. 在大数加法的结果中,首先找到最大值和最小值。然后遍历结果字符串,记录每个数字第一次出现的位置,并计算它们之间的最小差距。

关键点

进位的处理:逐位处理加法,并注意每一步的进位情况。 最大值与最小值的位差:遍历加法结果字符串中的每一位,记录最大和最小值的位置,然后计算它们之间的距离。

代码思路

  1. 输入两个字符串形式的超大数,例如 "111" 和 "34"
  2. 对两个字符串进行逐位相加,处理进位,得到加法结果。例如:"111" + "34" 得到 "145"
  3. 遍历加法结果 "145",找到最大数字 5 和最小数字 1,并计算它们之间的最小位差。结果为 1
  4. 4.返回最小位差作为最终结果。

代码如下

def add_large_numbers(num1: str, num2: str) -> str:
    # 获取两个数字的最大长度
    max_len = max(len(num1), len(num2))

    # 使用 zfill 填充零,确保两个字符串长度一致
    num1 = num1.zfill(max_len)
    num2 = num2.zfill(max_len)

    carry = 0  # 初始化进位
    result = []  # 存储加法结果

    # 从低位到高位逐位相加
    for i in range(max_len - 1, -1, -1):
        digit_sum = int(num1[i]) + int(num2[i]) + carry
        carry = digit_sum // 10  # 更新进位
        result.append(str(digit_sum % 10))  # 当前位的结果

    # 如果最后有进位,则添加到结果中
    if carry:
        result.append(str(carry))

    # 返回加法结果字符串(从高位到低位逆序)
    return ''.join(result[::-1])

def find_min_distance(sum_str: str) -> int:
    # 如果结果字符串中所有数字都相同,返回 0
    if len(set(sum_str)) == 1:
        return 0

    max_digit = max(sum_str)  # 找到最大值
    min_digit = min(sum_str)  # 找到最小值

    # 存储每个数字最近出现的位置
    last_pos = {}

    min_distance = len(sum_str)  # 初始化最小距离为一个较大的值

    # 遍历结果字符串
    for i, digit in enumerate(sum_str):
        # 如果当前数字是最大值或最小值
        if digit == max_digit or digit == min_digit:
            # 对比最大值和最小值之间的距离
            for prev_digit, prev_pos in last_pos.items():
                if (digit == max_digit and prev_digit == min_digit) or \
                   (digit == min_digit and prev_digit == max_digit):
                    min_distance = min(min_distance, i - prev_pos)
            # 更新当前位置
            last_pos[digit] = i

    # 返回最小距离
    return min_distance - 1 if min_distance != len(sum_str) else min_distance

def solution(string1: str, string2: str) -> int:
    # 先进行大数加法
    sum_result = add_large_numbers(string1, string2)
    # 然后计算位差
    return find_min_distance(sum_result)

if __name__ == "__main__":
    # 测试用例
    print(solution("111", "222"))  # 结果应为 0  
    print(solution("111", "34"))   # 结果应为 1  
    print(solution("999", "1"))    # 结果应为 0  
    print(solution("525", "474"))  # 结果应为 0  
    print(solution("5976762424003073", "6301027308640389"))  # 结果应为 6  
    print(solution("555", "444"))  # 结果应为 0  

时间复杂度

大数加法:在大数加法过程中,需要遍历每个数字的每一位,因此时间复杂度是 O(max(len(num1), len(num2))),其中 num1 和 num2 是输入数字字符串。

位差计算: 在位差计算过程中遍历加法结果字符串的每一位,因此时间复杂度是 O(n),其中 n 是加法结果字符串的长度。

因此总的时间复杂度是 O(n),其中 n 是加法结果字符串的长度。

思考

1.如果有更多的大数参与运算,可以尝试使用分布式算法或者借助 Python 内置的库来提升性能。

2.对于字符串的其他类似操作,比如查找特定字符的所有位置、计算字符的频率分布等,也可以通过类似的遍历和记录方式进行扩展。