leetcode: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.

第一眼看到这个题目,潜意识里觉得直接将字符串转换为数字相乘,然后将结果再转换为字符串,难道这题考的是字符串与数值之间的转换?

细看,发现数字可能非常大,那么问题来了:这个数据类型怎么定义呢?显然这种思路完全是错的了。

那么怎么解决这个问题呢?仔细一想问题可能在于如何理解这个乘法过程(题目中multiply可是关键字)了。由于经验尚浅,花了一些时间去琢磨,最后参照一些资料做出了如下分析:(算法题还是有很多值得用心思考的地方的,要学会抓住解决问题的痛点,和把握细节)

1、要模拟竖式乘法的计算过程(透过问题看本质)

2、这个过程有乘法思维,还有加法思维在里面(因为涉及到进位)

3、要把乘法和加法操作过程分清楚,每次一个新位与被乘数相乘之前,都要加上进位再处理。(注意细节)

4、为了顺应习惯,把两个数字reverse过来再操作,最后还原顺序。

代码如下:

class Solution {
public:
string multiply(string num1, string num2) {
    int m = num1.size(), n = num2.size();//字符串元素个数
    if (num1 == "0" || num2 == "0") return "0";
    vector<int> res(m+n, 0);
    reverse(begin(num1),end(num1));//字符串反转
    reverse(begin(num2),end(num2));
    for (int i = 0; i < n; ++i) 
        for (int idx = i, j = 0; j < m; ++j)
            res[idx++] += (num2[i]-'0')*(num1[j]-'0');// 字符转化为数字然后相乘(ascll码)

    int carry = 0;
    for (int i = 0; i < m+n; ++i) {
        int tmp = res[i];
        res[i] = (tmp+carry)%10; 
        carry = (tmp+carry)/10;//进位
    }

    string str(m+n,'0');
    for (int k = 0, i = res.size()-1; i >= 0; --i) str[k++] = res[i]+'0';//还原顺序
    auto idx = str.find_first_not_of('0');//将str字符串中第一个不匹配字符‘0’的索引值赋给idx
    return str.substr(idx);//从起始字符序号idx开始取得str中的子字符串(消除了前面的0)
}
};

 其他解法:

1、
class Solution { public: string multiply(string num1, string num2) { string sum(num1.size() + num2.size(), '0'); for (int i = num1.size() - 1; 0 <= i; --i) { int carry = 0; for (int j = num2.size() - 1; 0 <= j; --j) { int tmp = (sum[i + j + 1] - '0') + (num1[i] - '0') * (num2[j] - '0') + carry; sum[i + j + 1] = tmp % 10 + '0'; carry = tmp / 10; } sum[i] += carry; } size_t startpos = sum.find_first_not_of("0"); if (string::npos != startpos) { return sum.substr(startpos); } return "0"; } };

 

This is an example of the pretty straightforward but very efficient C++ solution with 8ms runtime on OJ. It seems most of people here implemented solutions with base10 arithmetic, however that is suboptimal. We should use a different base.

This was a hint. Now stop, think, and consider coding your own solution before reading the spoiler below.

The idea used in the algorithm below is to interpret number as number written in base 1 000 000 000 as we decode it from string. Why 10^9? It is max 10^n number which fits into 32-bit integer. Then we apply the same logic as we used to hate in school math classes, but on digits which range from 0 to 10^9-1.

You can compare the multiplication logic in other posted base10 and this base1e9 solutions and you'll see that they follow exactly same pattern.

Note, that we have to use 64-bit multiplication here and the carry has to be a 32-bit value as well

class Solution {
public:
    void toBase1e9(const string& str, vector<uint32_t>& out)
    {
        int i = str.size() - 1;
        uint32_t v = 0;
        uint32_t f = 1;
        do
        {
            int n = str[i] - '0';
            v = v + n * f;
            if (f == 100000000) {
                out.push_back(v);
                v = 0;
                f = 1;
            }
            else {
                f *= 10;
            }
            i--;
        } while (i >= 0);
        if (f != 1) {
            out.push_back(v);
        }
    }

    string fromBase1e9(const vector<uint32_t>& num)
    {
        stringstream s;
        for (int i = num.size() - 1; i >= 0; i--) {
            s << num[i];
            s << setw(9) << setfill('0');
        }
        return s.str();
    }

    string multiply(string num1, string num2)
    {
        if (num1.size() == 0 || num2.size() == 0) 
            return "0";
        vector<uint32_t> d1;
        toBase1e9(num1, d1);
        vector<uint32_t> d2;
        toBase1e9(num2, d2);
        vector<uint32_t> result;
        for (int j = 0; j < d2.size(); j++) {
            uint32_t n2 = d2[j];
            int p = j;
            uint32_t c = 0;
            for (int i = 0; i < d1.size(); i++) {
                if (result.size() <= p)
                    result.push_back(0);
                uint32_t n1 = d1[i];
                uint64_t r = n2;
                r *= n1;
                r += result[p];
                r += c;
                result[p] = r % 1000000000;
                c = r / 1000000000;
                p++;
            }
            if (c) {
                if (result.size() <= p)
                    result.push_back(0);
                result[p] = c;
            }
        }

        return fromBase1e9(result);
    }
};

  

 

 

posted @ 2015-06-09 13:34  小金乌会发光-Z&M  阅读(209)  评论(0编辑  收藏  举报