有趣的算法题之如何实现大整数相加

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zgcqflqinhao/article/details/84745499

原文:微信公众号:程序员小灰——如何实现大整数相加?(修订版)

1 题目

两个很大很大的整数,如何求出它们的和?

2 思路

我们平时在程序中求和就是直接定义两个 int (-2 的 31 次方到 2 的 31 次方 -1)类型的数,稍大一点的数用 long (-2 的 63 次方到 2 的 63 次方 -1)类型,基本都能满足平时的需求,那如果需要求两个超过 long 范围的整数的和,那么应该怎么办?

其实很简单,就跟我们小时候学大数相加的时候一样,用竖式来计算:

这样把竖式一列,不管多大的数,小学生都能算出来,开始分解动作。

第一步,把两个整数的每一个字符对应的整数取出来倒序存储,倒序存储是为了符合从左往右访问数组的习惯:

第二步,创建一个比两个数的长度的较大值 +1 的数组用于存放结果,+1 是考虑进 1 的情况:

第三步,从左往右遍历两个数组,相同下标的值相加,如下标为 0 时,8+9=17,把个位的 7 填到结果数组中的下标 0 的位置上,进的 1 放到下一位,即下标 1 的位置上:

第四步,下标为 1 时,1+2=3,再加上之前进的 1,所以下标 1 的值最终为 4:

继续遍历直到所有元素相加完毕:

最后再将结果数组再次倒序回来,如果首位没有进 1,有 0 的话,去掉首位的 0 就是最终结果:

3 代码实现

public class BigNumberSumDemo {
    @Test
    public void testBigNumberSum() {
        bigNumberSum("426709752318", "95481253129");
    }

    /**
     * author:MrQinshou
     * Description:求两个大整数相加的和
     * date:2018/12/4 21:02
     * param
     * return
     */
    public static String bigNumberSum(String num1, String num2) {
        // 确定结果数组的长度为两个字符串的较大值 +1,因为最后一位
        // 可能会进位,所以要 +1
        int resultLength = num1.length() > num2.length() ? num1.length() + 1 : num2.length() + 1;
        System.out.println("num1.length()--->" + num1.length()
                + ",num2.length()--->" + num2.length()
                + ",newLength--->" + resultLength);
        // 将 num1 转为 int 数组,长度为结果数组的长度,多余的位数为 0
        int[] num1Array = new int[resultLength];
        for (int i = 0; i < num1.length(); i++) {
            // 倒序存储,charAt() 方法获取到的是 char 类型的值,是字符对应的 ASCII 码
            // 再减去 '0' 对应的 ASCII 码即为原整数值
            num1Array[i] = num1.charAt(num1.length() - i - 1) - '0';
        }
        System.out.println("num1Array--->" + Arrays.toString(num1Array));
        // 将 num2 转为 int 数组,长度为结果数组的长度,多余的位数为 0
        int[] num2Array = new int[resultLength];
        for (int i = 0; i < num2.length(); i++) {
            // 倒序存储,charAt() 方法获取到的是 char 类型的值,是字符对应的 ASCII 码
            // 再减去 '0' 对应的 ASCII 码即为原整数值
            num2Array[i] = num2.charAt(num2.length() - i - 1) - '0';
        }
        System.out.println("num2CharArray--->" + Arrays.toString(num2Array));
        int[] result = new int[resultLength];
        for (int i = 0; i < resultLength; i++) {
            // 因为有可能有进位,所以先取出 result[i],定义为 temp
            int temp = result[i];
            // 然后 temp 再与 num1、num2 相应下标的整数相加
            temp += num1Array[i];
            temp += num2Array[i];
            // 如果结果大于等于 10 则当前下标只保留个位,下一个下标的数 +1,即进位
            if (temp >= 10) {
                temp -= 10;
                result[i + 1] = 1;
            }
            result[i] = temp;
            System.out.println("result--->" + Arrays.toString(result));
        }
        StringBuilder stringBuilder = new StringBuilder();
        // 定义一个标志位来记录遍历结果数组时遇到的 0 是不是开头的 0
        boolean notStartZero = true;
        // 再次倒序输出,即为正序结果
        for (int i = resultLength - 1; i >= 0; i--) {
            // 开头的 0 则跳过
            if (result[i] == 0 && notStartZero) {
                continue;
            }
            notStartZero = false;
            stringBuilder.append(result[i]);
        }
        System.out.println("sum--->" + stringBuilder.toString());
        return stringBuilder.toString();
    }
}

运行后结果如下:

4 总结

这个题目并不算难,先将两个加数倒序、创建结果数组、各位相加、结果再次倒序的时间复杂度都是 O(n),所以整个算法的时间复杂度也是  O(n)。

猜你喜欢

转载自blog.csdn.net/zgcqflqinhao/article/details/84745499