Leetcode:Multiply Strings 大数乘法 字符串乘法

Multiply Strings

Given two numbers represented as strings, return multiplication of the numbers as a string.

Note: The numbers can be arbitrarily large and are non-negative.

 

解题分析:

大数乘法,我们可以使用一个数组模拟乘法操作

这里有个陷阱,数组我们是采用char数组还是int数组,很自然的想到用string,也就是char数组,但是string会出错

我们假设有一位是9×9=81,然后81 + ‘0’ = 81 + 48 = 129 超出了 char的表示范围[-128, 127], 会出现截断

我们采用int数组就可以解决此问题

 

class Solution {
public:
    string multiply(string num1, string num2) {
        if (num1.size() == 0 || num2.size() == 0) return "";
        reverse(num1.begin(), num1.end());
        reverse(num2.begin(), num2.end());
        
        vector<int> result(num1.size() + num2.size(), 0);
        int count = 0;
        for (int i = 0; i < num1.size(); ++i) {
            for (int j = 0; j < num2.size(); ++j) {
                result.at(i+j) += (num1.at(i) - '0') * (num2.at(j) - '0');
            }
        }
        for (int i = 0; i < result.size(); ++i) {
            int tmp = result.at(i) + count;
            result.at(i) = tmp % 10;
            count = tmp / 10;
        }
        
        int zeroPos = 0;
        for (zeroPos = result.size() - 1; zeroPos >= 0; --zeroPos) {
            if (result.at(zeroPos) != 0) break;
        }
        result.erase(result.begin() + zeroPos + 1, result.end());
        reverse(result.begin(), result.end());
        
        string res(result.size(), '0');
        for (int i = 0; i < result.size(); ++i) {
            res.at(i) += result.at(i);
        }
        
        
        if (res == "") {
            return "0";
        } else {
            return res;
        }
    }
};

 

1. 我们首先开辟一个vector,长度为 两个字符串长度值和

两个数相乘,结果的位数之和一定 <= 两乘数的位数之和

2. 计算每位之和,先不管进位,一定要注意是累加

因为乘法都是从最低位开始操作的,如果直接从string的最末尾操作,下标计算就会异常繁琐而且非直观,故我们首先先反转两个乘数,直观操作

 result.at(i+j) += (num1.at(i) - '0') * (num2.at(j) - '0');

3. 处理进位

 result.at(i) = tmp % 10;

4. 舍弃vector末尾0,因为我们开辟的vector是 >= 正确的结果值位数的,所以可能存在 末尾无用的0

例如  12 × 2 = 24  vector里面存储的是 result[0] = 4  result[1] = 2, result[2] = 0

所以我们要从末尾开始查找,去除末尾连续的0,找到第一个非0值下标,然后erase

为什么要从末尾向前查找呢?  因为会出现 12004这样的情况

 

5. 最后 如果 string为空,则返回"0"  这是因为 "0" * "0" = "00" 然后我们查找第一个非0,然后erase,这样string就为空了

既然如下总结所示,无用的进位0只可能出现在最高位,对应于result的最末位,那么我们可不可以直接erase最末一位就可以呢?

不可以,因为可能是 "9899" * "0" = "00000" 我们erase最末一位仍然格式不正确

所以必须从末尾向前开始查找第一个非0元素,然后erase其位置以后所有的0,当然这会出现 将"00000"全部擦除, 这是我们单独返回“0”

 

总结:

大数乘法:res.size()只可能为 num1.size() + num2.size() - 1num1.size() + num2.size() 这两种情况,

并且无用的前置进位0只可能出现最高位num1.size() + num2.size()位置上

 

大数加法:res.size()只可能为 std::max(num1.size(), num2.size())std::max(num1.size(), num2.size()) + 1 这两种情况,

并且无用的前置进位0只可能出现最高位std::max(num1.size(), num2.size()) + 1位置上

你可能感兴趣的:(LeetCode)