一、大数和中的极值位距离
问题描述
小R面对一个问题,她有两个由数字字符组成的超大字符串数,需要求出这两个数相加后得到的字符串数中的最大数和最小数之间的位数差距。如果结果中所有数字都相同,则差距为 0。如果存在多个符合最大或最小条件的数,应该选择最小的位置差。
例如,字符串数 "111" 和 "222" 相加得到 "333",所有数字相同,因此位数差为 0。另一例子,字符串数 "111" 和 "34" 相加得到 "145",其中最大数是 '5' 位于第 3 位,最小数是 '1' 位于第 1 位,他们之间的位差为 1。
测试样例
样例1:
输入:
string1 = "111",string2 = "222"
输出:0
样例2:
输入:
string1 = "111",string2 = "34"
输出:1
样例3:
输入:
string1 = "999",string2 = "1"
输出:0
样例3:
输入:
string1 = "525",string2 = "474"
输出:0
二、解题思路
-
字符串相加:
- 首先,我们需要将两个字符串表示的数字相加。由于字符串可能表示的数字很大,我们不能直接将其转换为整数进行计算。我们使用逐位相加的方法,通过遍历字符串的每一位,从最低位(右侧)开始相加,并处理进位。
-
找出最大和最小数字:
- 在得到的和
(sum)中,我们需要找到其中的最大数字和最小数字。我们同时记录下这些数字的位置(索引)。为此,我们可以遍历和字符串的每一位,使用两个变量分别存储当前遇到的最大和最小数字,并使用两个列表保存它们出现的所有索引。
- 在得到的和
-
计算位置差:
- 在找到了所有的最大和最小数字及其位置后,我们需要计算它们之间的
最小位置差。为了得到最小差值,我们可以对最大数字的位置列表和最小数字的位置列表进行双重遍历,计算所有可能的差值,并更新最小差值。
- 在找到了所有的最大和最小数字及其位置后,我们需要计算它们之间的
-
处理特殊情况:
- 如果最大数字和最小数字相同(即和中的所有数字都相同),则位置差为
0,直接返回0。
- 如果最大数字和最小数字相同(即和中的所有数字都相同),则位置差为
-
返回结果:
- 最后,返回最小位置差的值。
三、solution函数
import java.util.ArrayList;
public class Main {
public static int solution(String string1, String string2) {
// 1. 将两个字符串表示的数字相加
String sum = addStrings(string1, string2);
// 初始化最大和最小数字的字符以及它们的位置列表
char maxDigit = Character.MIN_VALUE;
char minDigit = Character.MAX_VALUE;
ArrayList<Integer> maxIndices = new ArrayList<>();
ArrayList<Integer> minIndices = new ArrayList<>();
// 遍历字符串,找到最大和最小数字的字符以及它们的位置
for (int i = 0; i < sum.length(); i++) {
char currentDigit = sum.charAt(i);
if (currentDigit > maxDigit) {
maxDigit = currentDigit;
maxIndices.clear();
maxIndices.add(i);
} else if (currentDigit == maxDigit) {
maxIndices.add(i);
}
if (currentDigit < minDigit) {
minDigit = currentDigit;
minIndices.clear();
minIndices.add(i);
} else if (currentDigit == minDigit) {
minIndices.add(i);
}
}
// 计算最小位置差
int minDiff = Integer.MAX_VALUE;
for (int maxIndex : maxIndices) {
for (int minIndex : minIndices) {
minDiff = Math.min(minDiff, Math.abs(maxIndex - minIndex));
}
}
// 如果最大和最小数字相同,则返回0
if (maxDigit == minDigit) {
return 0;
}
// 返回最小位置差
System.out.println("sum:" + sum);
System.out.println("maxDigit:" + maxDigit);
System.out.println("minDigit:" + minDigit);
System.out.println("minDiff:" + minDiff);
return minDiff - 1;
}
// 辅助方法:将两个字符串表示的数字相加
private static String addStrings(String num1, String num2) {
StringBuilder result = new StringBuilder();
int carry = 0;
int i = num1.length() - 1;
int j = num2.length() - 1;
while (i >= 0 || j >= 0 || carry > 0) {
int sum = carry;
if (i >= 0) {
sum += num1.charAt(i--) - '0';
}
if (j >= 0) {
sum += num2.charAt(j--) - '0';
}
result.insert(0, sum % 10);
carry = sum / 10;
}
return result.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);
}
}
四、时间和空间复杂度分析
时间复杂度分析
-
字符串相加(
addStrings方法) :- 在这个方法中,我们需要遍历两个字符串的每一位。设
m为string1的长度,n为string2的长度。最坏情况下,我们需要遍历所有位数,所以时间复杂度为 O(max(m,n))。
- 在这个方法中,我们需要遍历两个字符串的每一位。设
-
查找最大和最小数字(
solution方法) :- 在这个方法中,我们遍历和字符串
sum的每一位来找出最大和最小数字。假设sum的长度为k,则这一步的时间复杂度为O(k)。
- 在这个方法中,我们遍历和字符串
-
计算最小位置差:
- 对于最大和最小数字的位置列表,我们需要进行双重遍历。假设最大数字的位置有
a个,最小数字的位置有b个,这部分的时间复杂度为 O(a×b)O(a×b)。在最坏情况下,如果所有数字都不同,a和b可以接近于k,所以这部分的复杂度可以被视作O(k²)。
- 对于最大和最小数字的位置列表,我们需要进行双重遍历。假设最大数字的位置有
综合来看,整个 solution 方法的时间复杂度为:O( m + n+ k + a × b) ≈ O( m + n + k²)
空间复杂度分析
-
存储结果字符串:
addStrings方法中使用了一个StringBuilder来存储相加的结果,空间复杂度为O(k),其中 k 是结果字符串的长度。
-
存储最大和最小数字的索引:
- 在
solution方法中,我们使用了两个ArrayList分别存储最大和最小数字的位置。最坏情况下,它们的大小也可以达到O(k)。
- 在
因此,整体的空间复杂度为:O(k)