• 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);
        }
    };
    

      

     

  • 相关阅读:
    Entity Framework Code-First(10.3):Property Mappings
    Entity Framework Code-First(10.2):Entity Mappings
    Entity Framework Code-First(10.1):EntityTypeConfiguration
    Entity Framework Code-First(10):Fluent API
    Entity Framework Code-First(9.11):DataAnnotations
    Entity Framework Code-First(9.10):DataAnnotations
    Entity Framework Code-First(9.9):DataAnnotations
    Entity Framework Code-First(9.8):DataAnnotations
    Entity Framework Code-First(9.7):DataAnnotations
    JAVA-初步认识-第六章-类与对象体现
  • 原文地址:https://www.cnblogs.com/carsonzhu/p/4563268.html
Copyright © 2020-2023  润新知