大数和中的极值位| 豆包MarsCode AI刷题

49 阅读5分钟

问题描述

小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

解题思路

题目说明字符串为超大字符串数,所以将字符串转为数字相加的思路是不行的。题目还要求如果存在多个符合最大或最小条件的数,应该选择最小的位置差。所以在最后找到最大数和最小数的集合之后还需要遍历找到最小的位置差。

实现步骤

  1. 字符串相加:实现两个大数的字符串相加,得到结果字符串。
  2. 找到最大和最小数字:遍历结果字符串,找到最大和最小数字。
  3. 记录位置:记录所有最大和最小数字的位置。
  4. 计算最小位数差:遍历所有最大和最小数字的位置,计算它们之间的最小位数差。

代码实现

#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
std::string addStrings(const std::string &num1, const std::string &num2) {
  // 实现字符串相加的逻辑
  std::string result;
  int carry = 0;
  int i = num1.size() - 1;
  int j = num2.size() - 1;

  while (i >= 0 || j >= 0 || carry > 0) {
    int digit1 = (i >= 0) ? num1[i] - '0' : 0;
    int digit2 = (j >= 0) ? num2[j] - '0' : 0;
    int sum = digit1 + digit2 + carry;
    carry = sum / 10;
    result.push_back(sum % 10 + '0');
    i--;
    j--;
  }
  std::reverse(result.begin(), result.end());
  // 返回相加后的字符串
  return result;
}

int solution(std::string string1, std::string string2) {
  // 调用 addStrings 函数得到相加后的结果
  std::string sum = addStrings(string1, string2);

  // 找到最大和最小的数字
  char max_digit = *std::max_element(sum.begin(), sum.end());
  char min_digit = *std::min_element(sum.begin(), sum.end());
  // 找到所有最大数和最小数的位置
  std::vector<int> max_positions;
  std::vector<int> min_positions;

  for (int i = 0; i < sum.size(); ++i) {
    if (sum[i] == max_digit) {
      max_positions.push_back(i);
    }
    if (sum[i] == min_digit) {
      min_positions.push_back(i);
    }
  }

  // 计算最小位数差
  int min_diff = sum.size(); // 初始化为一个较大的值
  for (int max_pos : max_positions) {
    for (int min_pos : min_positions) {
      int diff = std::abs(max_pos - min_pos);
      if (diff < min_diff) {
        min_diff = diff;
      }
    }
  }

  // 返回最小位数差
  if (min_diff == 0) {
    return 0;
  }
  return min_diff - 1;
  // // 计算最大数和最小数之间的位数差
  // int max_pos = sum.find(max_digit);
  // int min_pos = sum.find(min_digit);

  // // 返回位数差
  // if(std::abs(max_pos - min_pos ) == 0){return 0;}
  // return std::abs(max_pos - min_pos-1 );
}

int main() {
  //  You can add more test cases here
  std::cout << (solution("111", "222") == 0) << std::endl;
  std::cout << (solution("111", "34") == 1) << std::endl;
  std::cout << (solution("5976762424003073", "6301027308640389") == 6)
            << std::endl;

  return 0;
}

代码说明

字符串相加函数 addStrings 步骤:

  1. 初始化result 用于存储结果,carry 用于处理进位,i 和 j 分别指向两个字符串的末尾。
  2. 循环:从字符串的末尾开始逐位相加,直到两个字符串都处理完且没有进位。
  3. 处理进位:计算当前位的和,更新进位,并将当前位的结果存储在 result 中。
  4. 反转结果:由于结果是从低位到高位存储的,需要反转 result 以得到正确的顺序。

主函数步骤:

  1. 调用 addStrings:将两个字符串相加,得到结果字符串 sum
  2. 找到最大和最小数字:使用 std::max_element 和 std::min_element 找到结果字符串中的最大和最小数字。
  3. 记录位置:遍历结果字符串,记录所有最大和最小数字的位置。
  4. 计算最小位数差:遍历所有最大和最小数字的位置,计算它们之间的最小位数差。
  5. 返回结果:如果最小位数差为0,返回0;否则返回最小位数差减1。

复杂度分析

时间复杂度

addStrings 函数时间复杂度:O(n),因为循环次数最多为 n 次(两个字符串的长度之和),且std::reverse 的时间复杂度为 O(n)。

 solution 函数时间复杂度:O(n^2), 计算最小位数差的时间复杂度为 O(m * k),其中 m 和 k 分别是最大和最小数字位置的数量,最坏情况下为 O(n^2)。

空间复杂度

addStrings 函数空间复杂度:O(n),其中 n 是两个字符串中较长的那个字符串的长度。

 solution 函数 空间复杂度:O(n),其中 n 是结果字符串的长度。

总结

这个题目主要考察了对字符串操作、遍历和计算的能力。通过实现字符串相加、找到最大和最小数字、记录位置、计算最小位数差等步骤,可以有效地解决这个问题。代码的时间复杂度为 O(n^2),空间复杂度为 O(n),其中 n 是结果字符串的长度。