大数和中的极值位距离
问题描述
小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
样例4:
输入:
string1 = "525",string2 = "474"
输出:0
代码
#include <string>
#include <algorithm>
#include <unordered_map>
#include <climits>
using namespace std;
// 实现大数加法
string add_large_numbers(const string& num1, const string& num2) {
int len1 = num1.size();
int len2 = num2.size();
int max_len = max(len1, len2);
string n1 = string(max_len - len1, '0') + num1; // 补齐前导0
string n2 = string(max_len - len2, '0') + num2;
string result;
int carry = 0;
// 从右向左逐位相加
for (int i = max_len - 1; i >= 0; --i) {
int digit_sum = (n1[i] - '0') + (n2[i] - '0') + carry;
carry = digit_sum / 10;
result.push_back((digit_sum % 10) + '0');
}
// 处理最后的进位
if (carry) {
result.push_back(carry + '0');
}
reverse(result.begin(), result.end());
return result;
}
// 找到最大值和最小值的最小位置差
int find_min_distance(const string& sum_str) {
if (sum_str.empty()) return 0;
char max_digit = *max_element(sum_str.begin(), sum_str.end());
char min_digit = *min_element(sum_str.begin(), sum_str.end());
if (max_digit == min_digit) return 0; // 如果所有数字都相同
unordered_map<char, int> last_pos;
int min_distance = INT_MAX;
for (int i = 0; i < sum_str.size(); ++i) {
char digit = sum_str[i];
if (digit == max_digit || digit == min_digit) {
for (const auto& [prev_digit, prev_pos] : last_pos) {
if ((digit == max_digit && prev_digit == min_digit) ||
(digit == min_digit && prev_digit == max_digit)) {
min_distance = min(min_distance, i - prev_pos);
}
}
last_pos[digit] = i;
}
}
return min_distance == INT_MAX ? 0 : min_distance - 1;
}
// 主函数:计算两个大数相加后的最大最小值位置差
int solution(const string& string1, const string& string2) {
string sum_result = add_large_numbers(string1, string2);
return find_min_distance(sum_result);
}
int main() {
// 测试用例
cout << (solution("111", "222") == 0) << endl; // 结果是"333",所有数字相同,差距为0
cout << (solution("111", "34") == 1) << endl; // 结果是"145",最大值5和最小值1的位置差为1
cout << (solution("999", "1") == 0) << endl; // 结果是"1000",最大值1和最小值0的位置差为0
cout << (solution("525", "474") == 0) << endl; // 结果是"999",所有数字相同,差距为0
cout << (solution("5976762424003073", "6301027308640389") == 6) << endl; // 大数测试
// 额外测试用例
cout << (solution("99", "1") == 0) << endl; // 结果是"100",测试进位情况
cout << (solution("555", "444") == 0) << endl; // 结果是"999",测试全相同数字
return 0;
}
详细解答
功能描述
这段代码实现了:
-
大数加法: 用字符串模拟大数运算,解决普通整数计算可能溢出的问题。
-
最大最小值的最小位置差: 在两个大数相加的结果中,找到最大数字和最小数字的最近位置差。
代码分析
add_large_numbers
函数:
输入两个字符串表示的大数,返回它们的和。
具体实现:
- 使用 `zfill` 思想:将较短的数字前面补零,确保两数长度相同。
- 从最低位开始逐位相加,记录进位。
- 结果倒序存储,最后再反转,返回最终的字符串。
复杂度分析:
- 时间复杂度:`O(n)`,`n` 是两个字符串的最大长度。
- 空间复杂度:`O(n)`,用于存储结果。
-
find_min_distance
函数:-
输入加法结果字符串,返回最大值和最小值的最小位置差。
-
具体实现:
- 使用 STL 函数
max_element
和min_element
找到最大、最小数字。 - 遍历字符串,记录最大和最小值的位置,用哈希表 (
unordered_map
) 存储每个数字的最新位置。 - 动态更新最小位置差。
- 使用 STL 函数
-
复杂度分析:
- 时间复杂度:
O(n)
,n
是字符串长度。 - 空间复杂度:
O(1)
,使用固定大小的哈希表。
- 时间复杂度:
-
-
solution
函数:- 调用
add_large_numbers
计算大数和,调用find_min_distance
计算最小位置差。 - 时间复杂度为两部分之和:
O(n)
。
- 调用
测试用例解读
-
用例 1:
solution("111", "222")
大数和:
333
,所有数字相同,差距为 0。 -
用例 2:
solution("111", "34")
大数和:
145
,最大值5
,最小值1
,位置差为 1。 -
用例 3:
solution("999", "1")
大数和:
1000
,最大值1
,最小值0
,最近差为 0。 -
用例 4:
solution("5976762424003073", "6301027308640389")
大数和:
12277789732643462
,最大值9
和最小值2
最近距离为 6。
总结
-
优点:
可扩展性: 适用于任意长度的大整数计算。
高效性: 基于字符串操作,避免整型溢出,同时实现了线性复杂度的距离计算。
模块化设计: 各功能独立易于测试。
-
不足:
内存开销: 对大数计算需要存储完整的字符串,不适合超大规模数据处理。
生活中的应用
-
金融计算:
大数运算常用于银行系统中对超大金额的累加,如股票市场的交易总金额计算。
-
加密技术:
公钥加密算法(如 RSA)中涉及大整数加法、乘法等操作。
-
科学研究:
天文学、物理学中的数据计算,常涉及超大数。