zoukankan      html  css  js  c++  java
  • 43. 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.

    链接:  http://leetcode.com/problems/multiply-strings/

    题解: 

    大数乘法,建立一个数组,保存每一位乘出来的数字,然后再保存成字符串就可以了。跟add two number一类的很像。

    Time Complexity - O(m * n), Space Complexity - O(m + n)。

    public class Solution {
        public String multiply(String num1, String num2) {          //Big Integer multiplying
            if(num1 == null || num2 == null || num1.length() == 0 || num2.length() == 0)
                return "";
            int num1Len = num1.length(), num2Len = num2.length();
            int[] resArr = new int[num1Len + num2Len];
            
            for(int i = num1Len - 1; i >= 0; i--) {
                for(int j = num2Len - 1; j >= 0; j--) {
                    int index = (num1Len - 1 - i) + (num2Len - 1 - j);      //stored the data increasingly
                    resArr[index] += (num1.charAt(i) - '0') * (num2.charAt(j) - '0');
                    resArr[index + 1] += resArr[index] / 10;
                    resArr[index] %= 10;
                }
            }
            
            StringBuilder res = new StringBuilder();
            
            for(int i = resArr.length - 1; i > 0; i--) {
                if(res.length() == 0 && resArr[i] == 0)
                    continue;
                res.append(resArr[i]);
            }
            
            res.append(resArr[0]);
            return res.toString();
        }
    }

    二刷:

    一刷的逻辑相当不清楚啊...当时怎么糊弄过去的...现在就好一些。主要思路是:

    1. 两数相乘,结果的长度不会大于两数长度和m + n,所以一开始我们开一个int[] res = new int[m + n]
    2. 接下来对num1和num2做一个双重循环从后向前遍历
      1. 当前的 digit1 = num1.charAt(i) - '0',  digit2 = num2.charAt(j) - '0'
      2. 这时我们可以更新当前res[i + j + 1]的这个位置为原来存在这一位置上的值再加上新的值digits 1 * digit2,简略一下就是 res[i + j + 1] += digits 1 * digit2 
      3. 接下来根据res[i + j + 1]的新值,我们可以更新高一位的res[i + j],  res[i + j] += res[i + j + 1] / 10,就是本来的值加上进位
      4. 最后我们再用res[i + j + 1] %= 10求出这一位置进位后剩下的digit
    3. 求出res数组之后我们可以建立一个StringBuilder sb,来从头遍历数组,求出最终结果
      1. 要注意的是当sb.length() == 0并且res[i] = 0时,这时候是开头的0值,需要跳过
      2. 假如遍历完毕以后sb.length()依然等于0, 我们返回"0"

    Java:

    Time Complexity - O(mn),  Space Complexity - O(m + n)

    public class Solution {
        public String multiply(String num1, String num2) {
            if (num1 == null || num2 == null) {
                return "";
            }
            int m = num1.length(), n = num2.length();
            int[] res = new int[m + n];
            for (int i = m - 1; i >= 0; i--) {
                int digit1 = num1.charAt(i) - '0';
                for (int j = n - 1; j >= 0; j--) {
                    int digit2 = num2.charAt(j) - '0';
                    res[i + j + 1] += digit1 * digit2;
                    res[i + j] += res[i + j + 1] / 10;
                    res[i + j + 1] %= 10;    
                }
            }
            
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < res.length; i++) {
                if (sb.length() == 0 && res[i] == 0) {
                    continue;
                }
                sb.append(res[i]);
            } 
            if (sb.length() == 0) {
                sb.append(0);
            }
            return sb.toString();
        }
    }

    题外话:

    1/25/2016

    NWK到JSQ的Path还没有修好,所以今天周一WFH。需要提高刷题速度了,不然难以按照进度完成。 周五晚海投了50份简历试试水,估计不内推还是很难拿到回应。

    三刷:

    方法和一刷二刷一样。就是先开一个数组,把num1和num2每个digit的乘积保存起来, 再进行进位操作。

    要注意的是,在计算乘积的时候,num1的第i位和num2的第j位的乘积,要保存在数组的product[i + j + 1]这个位置里。用两个例子 "100 * 100"和"99 * 99"一计算就很容易能发现这个规律。 还有一点就是,最后乘积全为0的话要返回"0"。  去除乘积串前部的"0"可以用条件 if (digit != 0 || sb.length() > 0)。

    更好的方法应该是Karatsuba multiply,利用Divide and Conquer将复杂度降低到nlog2。留给以后了。

    Java:

    public class Solution {
        public String multiply(String num1, String num2) {
            if (num1 == null || num2 == null || num1.length() == 0 || num2.length() == 0) return "0";
            int len1 = num1.length(), len2 = num2.length();
            int[] product = new int[len1 + len2];
            for (int i = len1 - 1; i >= 0; i--) {
                int digit1 = num1.charAt(i) - '0';
                for (int j = len2 - 1; j >= 0; j--) {
                    int digit2 = num2.charAt(j) - '0';
                    product[i + j + 1] += digit1 * digit2;
                }
            }
            
            for (int i = product.length - 1; i >= 1; i--) {
                product[i - 1] += product[i] / 10;
                product[i] %= 10;
            }
            
            StringBuilder sb = new StringBuilder();
            for (int digit : product) {
                if (digit != 0 || sb.length() > 0) sb.append(digit);
            }
            if (sb.length() == 0) sb.append(0);
            
            return sb.toString();
        }
    }

    Update: 也可以像二刷一样把进位操作写到一个循环体里

    public class Solution {
        public String multiply(String num1, String num2) {
            if (num1 == null || num2 == null || num1.length() == 0 || num2.length() == 0) return "0";
            int len1 = num1.length(), len2 = num2.length();
            int[] product = new int[len1 + len2];
            for (int i = len1 - 1; i >= 0; i--) {
                int digit1 = num1.charAt(i) - '0';
                for (int j = len2 - 1; j >= 0; j--) {
                    int digit2 = num2.charAt(j) - '0';
                    product[i + j + 1] += digit1 * digit2;
                    product[i + j] += product[i + j + 1] / 10;
                    product[i + j + 1] %= 10;    
                }
            }
            
            StringBuilder sb = new StringBuilder();
            for (int digit : product) {
                if (digit != 0 || sb.length() > 0) sb.append(digit);
            }
            if (sb.length() == 0) sb.append(0);
            
            return sb.toString();
        }
    }

    Reference:

    http://www.cnblogs.com/springfor/p/3889706.html

    https://leetcodenotes.wordpress.com/2013/10/20/leetcode-multiply-strings-%E5%A4%A7%E6%95%B4%E6%95%B0%E7%9A%84%E5%AD%97%E7%AC%A6%E4%B8%B2%E4%B9%98%E6%B3%95/

    https://leetcode.com/discuss/71593/easiest-java-solution-with-graph-explanation

    https://leetcode.com/discuss/26602/brief-c-solution-using-only-strings-and-without-reversal

    https://leetcode.com/discuss/33951/ac-solution-in-java-with-explanation

    https://leetcode.com/discuss/29364/clear-java-solution-without-reversal

    http://introcs.cs.princeton.edu/java/99crypto/Karatsuba.java.html

    https://d396qusza40orc.cloudfront.net/algo1/slides/algo1-intro3_typed.pdf

  • 相关阅读:
    元组转换列表
    python切片
    序列类型的方法 增删改查
    python基础 四则运算和数据类型
    linux 常用基础命令操作
    MySQL 命令操作
    linux中如何修改root密码、设置固定IP、安装vmware tools
    虚拟机中网络桥接模式设置
    PHP基础
    HTML基本标签介绍
  • 原文地址:https://www.cnblogs.com/yrbbest/p/4436340.html
Copyright © 2011-2022 走看看