46.大数和中的极值位距离

63 阅读4分钟

问题描述

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

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

题目解析

目标:计算两个字符串形式的大整数相加后的结果中的最大数字和最小数字的距离差(按位置计算)。

核心规则:

  1. 字符串相加:将两个超大数相加,按照大整数的计算规则处理(从低位到高位逐位相加,考虑进位)。

  2. 定位最小值和最大值

    • 遍历结果字符串,找到最大数字和最小数字的位置;
    • 如果有多个最大或最小值,选最近的位置差;
    • 如果结果中最大值和最小值相等,直接返回差值为 0
  3. 输出差值:返回最小和最大值之间的最近距离。


解题思路

步骤 1:模拟字符串相加

使用逐位相加的方式处理大整数,确保精确性:

  • 从低位向高位处理,每次取对应位的数字相加;
  • 记录进位,追加到下一位;
  • 最后,如果还有进位,需要在最高位补充。

步骤 2:查找最小值与最大值的位置

遍历计算结果:

  • 保存所有出现的最小值和最大值的索引位置;
  • 如果当前数字比记录的最小值更小,则更新最小值及其位置;
  • 如果当前数字比记录的最大值更大,则更新最大值及其位置。

步骤 3:计算距离

  • 遍历最大值和最小值的位置,计算所有可能的位置差;
  • 记录最小差值。

图解流程

示例:

  • 输入:string1 = "999", string2 = "1"

  • 加法结果:"1000"

    • 最大值:'1',位置 0
    • 最小值:'0',位置 1, 2, 3
  • 最近位置差:

    • 1 - 0 = 1(选最近的)。

实现代码

java
复制代码
import java.util.ArrayList;
import java.util.List;

public class Main {
    public static int solution(String string1, String string2) {
        // Step 1: 模拟大整数相加
        StringBuilder result = new StringBuilder();
        int carry = 0;
        int len1 = string1.length();
        int len2 = string2.length();
        int maxLength = Math.max(len1, len2);
        
        for (int i = 0; i < maxLength; i++) {
            int digit1 = i < len1 ? string1.charAt(len1 - 1 - i) - '0' : 0;
            int digit2 = i < len2 ? string2.charAt(len2 - 1 - i) - '0' : 0;
            int sum = digit1 + digit2 + carry;
            result.append(sum % 10);
            carry = sum / 10;
        }
        
        if (carry != 0) {
            result.append(carry);
        }
        
        result.reverse();
        String sumResult = result.toString();

        // Step 2: 查找最大值和最小值的位置
        char minDigit = '9';
        char maxDigit = '0';
        List<Integer> minPositions = new ArrayList<>();
        List<Integer> maxPositions = new ArrayList<>();
        
        for (int i = 0; i < sumResult.length(); i++) {
            char digit = sumResult.charAt(i);
            if (digit < minDigit) {
                minDigit = digit;
                minPositions.clear();
                minPositions.add(i);
            } else if (digit == minDigit) {
                minPositions.add(i);
            }
            
            if (digit > maxDigit) {
                maxDigit = digit;
                maxPositions.clear();
                maxPositions.add(i);
            } else if (digit == maxDigit) {
                maxPositions.add(i);
            }
        }

        // Step 3: 计算最小距离
        if (minDigit == maxDigit) {
            return 0;
        }

        int minDifference = Integer.MAX_VALUE;
        for (int minPos : minPositions) {
            for (int maxPos : maxPositions) {
                int difference = Math.abs(maxPos - minPos);
                minDifference = Math.min(minDifference, difference);
            }
        }

        return minDifference;
    }

    public static void main(String[] args) {
        // 测试用例
        System.out.println(solution("999", "1") == 0);
        System.out.println(solution("111", "34") == 1);
        System.out.println(solution("145", "0") == 2);
        System.out.println(solution("5976762424003073", "6301027308640389") == 6);
    }
}

测试结果说明

  1. 用例 1

    • 输入:"999""1"
    • 加法结果:"1000"
    • 最大值:'1',位置 0
    • 最小值:'0',位置 1, 2, 3
    • 最近位置差为 1
  2. 用例 2

    • 输入:"111""34"
    • 加法结果:"145"
    • 最大值:'5',位置 2
    • 最小值:'1',位置 0
    • 最近位置差为 2 - 0 = 2
  3. 用例 3

    • 输入:"5976762424003073""6301027308640389"
    • 加法结果:"12277789732643462"
    • 最大值位置:6,最小值位置:0
    • 最近距离差为 6

复杂度分析

  1. 时间复杂度

    • 大整数相加:O(max(len1,len2))O(\max(len1, len2))
    • 遍历结果字符串查找最大最小值:O(L),其中L 为结果字符串长度;
    • 计算最小距离:O(M×N),其中 M 和 N 是最大和最小值的出现次数。

    综合时间复杂度:O(max(len1,len2)+M×N)O(max⁡(len1,len2)+M×N)

  2. 空间复杂度

    • 存储结果字符串:O(L);
    • 存储最大和最小值的位置:O(M+N)。

    总空间复杂度:O(L+M+N)。