青训营X豆包MarsCode 技术训练营第五课_大数和中的极值位距离

52 阅读6分钟

**大数和中的极值位距离 **

自己实现的算法是用的暴力解出来 感觉效率比较低 期望有大佬能给出更好的做法

问题描述

在日常的编程中,我们经常会遇到需要处理大数字的情况。比如计算两个非常大的整数的和,或是寻找两个大数之间的最大差值等。这种场景下,我们无法简单地使用 Java 或其他编程语言中的基本数据类型,因为它们都有存储范围的限制。相反,我们需要使用特殊的数据结构和算法来解决这类问题。

本题就是一个典型的大数处理问题。给定两个由数字字符组成的超大字符串,需要求出它们相加后得到的新字符串中,最大数和最小数之间的位数差距。如果结果中所有数字都相同,则差距为0。如果存在多个符合最大或最小条件的数字,应该选择最小的位置差。

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

解题思路

要解决这个问题,我们需要分为几个步骤:

  1. 首先实现一个能够处理大数相加的函数。由于Java中的基本数据类型无法存储这么大的数字,我们需要使用字符串来表示这些数字,并逐位相加来得到最终结果。

  2. 在得到相加结果之后,我们需要遍历这个字符串,找出其中的最大值和最小值。在遍历的同时,我们还需要记录下最大值和最小值出现的位置。

  3. 最后,我们需要比较最大值和最小值的位置差,并返回最小的位置差。如果所有数字都相同,则返回0。

在实现上述步骤时,需要注意以下几个关键点:

  1. 大数相加的实现:由于输入的数字可能非常大,我们无法使用Java中的基本数据类型来存储和计算它们。取而代之的是,我们需要使用字符串来表示这些数字,并逐位相加。这种方式虽然比直接使用基本数据类型要慢一些,但它可以处理任意大小的数字。

  2. 最大值和最小值的查找:在得到相加结果之后,我们需要遍历这个字符串,找出其中的最大值和最小值。同时,我们还需要记录下它们出现的位置,因为题目要求返回最小的位置差。

  3. 多个最大值或最小值的情况:如果存在多个符合最大或最小条件的数字,我们应该选择最小的位置差。因此,在记录最大值和最小值的位置时,需要使用列表来存储所有符合条件的位置。

通过这三个步骤,我们就可以完整地解决这个问题了。下面让我们看看具体的代码实现。

代码实现

在代码实现部分,我们首先定义了一个 addStrings() 函数,用于实现两个大数字字符串的相加操作。这个函数使用了一个 StringBuilder 来逐位相加并存储结果。

接下来,我们实现了 solution() 函数,它是本题的主要解决方案。在这个函数中,我们先调用 addStrings() 函数得到相加结果,然后遍历这个字符串,找出最大值和最小值以及它们出现的位置。

最后,我们比较最大值和最小值的位置差,并返回最小的位置差。如果所有数字都相同,则返回0。

通过这种方式,我们就成功地解决了这个大数相加的问题,并找出了最大值和最小值之间的位置差。

import java.util.*;
public class Main {
    // public static int solution(String string1, String string2) {
    //     // Please write your code here
    //     return -2;
    // }

    public static int solution(String string1, String string2) {
        String s=addStrings(string1,string2);
        int min=10,max=-1;
        int len = s.length();
        for(int i = 0; i< len; i++) {
            min = Math.min(min, s.charAt(i) - '0');
            max = Math.max(max, s.charAt(i) - '0');
        }
        if(min==max)return 0;
        ArrayList<Integer> min_list=new ArrayList<Integer>();
        ArrayList<Integer> max_list=new ArrayList<Integer>();
        for(int i = 0; i< len; i++){
            if(s.charAt(i)-'0'==min)
                min_list.add(i);
            if (s.charAt(i)-'0'==max)
                max_list.add(i);
        }
        int ans=len;
        for(int i=0;i<min_list.size();i++)
            for(int j=0;j<max_list.size();j++)
                ans=Math.min(Math.abs(min_list.get(i)-max_list.get(j))-1,ans);
        return ans;
    }

    private static String addStrings(String s1, String s2) {
        StringBuilder sb = new StringBuilder();
        int i = s1.length() - 1, j = s2.length() - 1;
        int carry = 0;
        while (i >= 0 || j >= 0) {
            int sum = carry;
            if (i >= 0) sum += s1.charAt(i--) - '0';
            if (j >= 0) sum += s2.charAt(j--) - '0';
            sb.append(sum % 10);
            carry = sum / 10;
        }
        if (carry != 0) sb.append(carry);
        return sb.reverse().toString();
    }
    public static void main(String[] args) {
        //  You can add more test cases here
        System.out.println(solution("111", "222") == 0);
        System.out.println(solution("111", "34") == 1);
        System.out.println(solution("5976762424003073", "6301027308640389") == 6);
        System.out.println(solution("2222222222222222222222","1")==0);
    }
}

复杂度分析

让我们来分析一下这个解决方案的时间复杂度和空间复杂度:

  1. 时间复杂度:

    • addStrings() 函数的时间复杂度为 O(m+n),其中 m 和 n 分别是两个输入字符串的长度。
    • solution() 函数中的遍历操作需要 O(m+n)的时间复杂度,其中 m+n 是最终相加结果的长度。
    • 最后比较最大值和最小值位置差的操作需要 O(mn)的时间复杂度,其中 m 和 n 分别是最大值和最小值出现的位置个数。
    • 因此,整个解决方案的总时间复杂度为 O(m+n+mn)。
  2. 空间复杂度:

    • addStrings() 函数需要使用一个 StringBuilder 来存储相加结果,因此空间复杂度为 O(m+n)。
    • solution() 函数中需要使用两个列表来存储最大值和最小值的位置,因此空间复杂度为 O(m+n)。
    • 因此,整个解决方案的总空间复杂度为 O(m+n)。

总的来说,这个解决方案的时间复杂度和空间复杂度都是可以接受的,能够很好地处理大数相加的问题。

结论

在日常编程中,我们经常会遇到需要处理大数字的场景。本文介绍了一个典型的大数相加问题,并提供了一种有效的解决方案。通过实现一个大数相加的函数,再找出最大值和最小值的位置,最后计算它们之间的位置差,我们就可以很好地解决这个问题。

这种方式不仅可以处理任意大小的数字,而且时间复杂度和空间复杂度也是可以接受的。希望通过本文的讲解,大家能够学会如何应对大数相关的编程问题,并在实际开发中灵活应用这些技巧。