Leetcode 43. 字符串相乘 中等

题目 - 点击直达

  • 1. 43. 字符串相乘 中等
    • 1. 题目详情
      • 1. 原题链接
      • 2. 题目要求
      • 3. 基础框架
    • 2. 思路一 做加法
      • 1. 思路分析
      • 2. 时间复杂度
      • 3. 代码实现
    • 3. 思路二 做乘法
      • 1. 思路分析
      • 2. 时间复杂度
      • 3. 代码实现

1. 43. 字符串相乘 中等

1. 题目详情

给定两个以字符串形式表示的非负整数 num1 和 num2,返回 num1 和 num2 的乘积,它们的乘积也表示为字符串形式。

注意:不能使用任何内置的 BigInteger 库或直接将输入转换为整数。

1. 原题链接

Leetcode 43. 字符串相乘 中等

2. 题目要求

示例 1:
输入: num1 = “2”, num2 = “3”
输出: “6”

示例 2:
输入: num1 = “123”, num2 = “456”
输出: “56088”

提示:
1 <= num1.length, num2.length <= 200
num1 和 num2 只能由数字组成。
num1 和 num2 都不包含任何前导零,除了数字0本身。

3. 基础框架

● Cpp代码框架

class Solution {
public:
    string multiply(string num1, string num2) {
    }
};

2. 思路一 做加法

1. 思路分析

( 1 ) (1) (1) 模拟两个数 n u m 1 num1 num1 n u m 2 num2 num2相乘的过程, n u m 1 num1 num1的每一位数字从个位开始依次与 n u m 2 num2 num2的每一位数字相乘分别得到一个结果数,最后把这些结果数再相加就得到了最后的相乘结果(相加需要用到字符串相加的知识)
( 2 ) (2) (2) n u m 1 num1 num1的某一位与 n u m 2 num2 num2所有位相乘得到的结果数需要存放在字符串中,由于运算顺序是从低位到高位进行的,所以为了保证结果数在字符串中按高位到低位排列就需要一直在字符串中头插数据,而头插的效率非常低;为了提高效率,我们选择结果数按低位到高位的顺序存放,这样只需一直尾插数据,效率很高;
( 3 ) (3) (3) 最后所有的结果数相加得到的也是相乘结果的倒序;
( 4 ) (4) (4) 逆置之前去除运算产生的可能存在的无效0:
逆置之前结果是反着的,左边是低位,右边是高位

  • 如果只有1位,且是0,是有效的0,不去除
  • 如果有多位,低位的0和中间的0是有效的0,不去除; 高位的0(可能有多个)是无效的,需要去除
    ( 5 ) (5) (5) 逆置得到需要的相乘结果;
    在这里插入图片描述

2. 时间复杂度

O ( m n + n 2 ) O(mn+n^2) O(mn+n2)
n u m 1 num1 num1的每一位都需要与 n u m 2 num2 num2的每一位相乘,共乘了 m n mn mn次;
相加的字符串长度不超过 m + n m + n m+n,字符串相加的操作共有n次,字符串相加的时间复杂度是 m n + n 2 mn + n^2 mn+n2;
综上,时间复杂度是 m n + n 2 mn+n^2 mn+n2

3. 代码实现

class Solution {
public:
    string multiply(string num1, string num2) {
        // 结果字符串
        string ret;
        for(int i = num1.size() - 1; i >= 0; --i){
            // num1的高位和低位与另一个数的每一位相乘的到的结果不能直接相加,高位比低位需要多乘个10才能相加;
            // 从个位开始,每高一位,就需要多乘一个10,个位相当于乘了0个10
            // 由于是从低位开始依次相乘,所以是倒着循环的,但是循环的结果是顺序存放的,最后需要逆置才是结果
            string tmp(num1.size() - i - 1, '0');
            int carry = 0;
            for(int j = num2.size() - 1; j >= 0; --j){
                int sum = (num1[i] - '0') * (num2[j] - '0') + carry;
                carry = sum / 10;
                tmp += sum % 10 + '0';
            }
            // 相乘 进位取值范围[0, 9],与相加的进位取值范围大[0,1]
            if(carry) tmp += carry + '0';
            // += 
            add(ret, tmp);
        }
        // 逆置之前结果是反着的,左边是低位,右边是高位
        // 如果只有1位,且是0,是有效的0,不去除
        // 如果有多位,低位的0和中间的0是有效的0,不去除; 高位的0(可能有多个)是无效的,需要去除
        // 末尾0 需要去除 可能存在多个末尾0
        while(ret.size() > 1 && ret[ret.size() - 1] == '0') ret.erase(ret.size() - 1, 1);
        reverse(ret.begin(), ret.end());
        return ret;
    }
    // 大数相加,且s1和s2中存放的数是倒序的
    // 例如:存放的是 1 2 3 4 实际上对应的值是 1234
    void add(string& s1, string& s2){
        int l1 = 0;
        int l2 = 0;
        int len1 = s1.size();
        int len2 = s2.size();
        int carry = 0;
        string s;
        while(l1 < len1 || l2 < len2){
            int num1 = l1 < len1 ? s1[l1] - '0' : 0;
            int num2 = l2 < len2 ? s2[l2] - '0' : 0;
            int sum = num1 + num2 + carry;
            carry = sum / 10;
            s += sum % 10 + '0';
            l1++;
            l2++;
        }
        if(carry) s += '1';
        s1 = s;
    }
};

3. 思路二 做乘法

1. 思路分析

( 1 ) (1) (1) 大小为 l e n 1 len1 len1的字符串 n u m 1 num1 num1和大小为 l e n 2 len2 len2的字符串 n u m 2 num2 num2,依然是数 n u m 1 num1 num1的每一位依次乘以 n u m 2 num2 num2的每一位;
与做加法思路不同的是:不是再 ′ ′ '' ′′等到 n u m 1 num1 num1的这一位数与 n u m 2 num2 num2的所有位上的数相乘得到所有的中间结果字符串,再把所有中间结果字符串相加 ′ ′ '' ′′,而是 n u m 1 num1 num1的这一位数与 n u m 2 num2 num2的一位数相乘后就放在最终结果字符串中的对应位置;
但是直接放在字符串中还是会涉及到字符串加法操作,为了简化操作,先用数组保存结果,等到 n u m 1 num1 num1 n u m 2 num2 num2的所有位相乘完后再把数组中的结果复制到字符串中;
( 2 ) (2) (2) 依旧是从低位开始相乘,使用下标 i i i j j j分别表示当前 n u m 1 num1 num1 n u m 2 num2 num2进行相乘的位的下标;
( 3 ) (3) (3) 计算 n u m 1 [ i ] + n u m 2 [ j ] + a [ i + j + 1 ] num1[i]+num2[j]+a[i+j+1] num1[i]+num2[j]+a[i+j+1]的结果 s u m sum sum i + j + 1 i+j+1 i+j+1就是 s u m sum sum将要存放的位置,如果 s u m sum sum 大于等于10就除10并产生进位 c a r r y carry carry,把进位 c a r r y carry carry加入到 i + j i+j i+j位置内
( 4 ) (4) (4) 结果长度的范围是 [ l e n 1 + l e n 2 − 1 , l e n 1 + l e n 2 ] [len1+len2-1, len1+len2] [len1+len21,len1+len2],如果高位存在多余的1个及以上的0时需要去除;
( 5 ) (5) (5) 数组中的结果复制到字符串中;
在这里插入图片描述

2. 时间复杂度

O ( n m ) O(nm) O(nm)
n u m 1 num1 num1 n u m 2 num2 num2所有的位数都要相乘一次,共相乘 n m nm nm次,¥¥每一次的相加操作再整型数组中进行,是 n m nm nm次;

3. 代码实现

class Solution {
public:
    string multiply(string num1, string num2) {
        int len1 = num1.size();
        int len2 = num2.size();
        // 结果的位数范围[len1+len2-1, len1+len2];
        int a[len1 + len2];
        memset(a, 0, sizeof(int) * (len1 + len2));
        for(int i = len1 - 1; i >= 0; --i){
            for(int j = len2 - 1; j >= 0; --j){
            	// 正着存数据
                int pos = i + j + 1;
                int sum = (num1[i] - '0') * (num2[j] - '0') + a[pos];
                a[pos] = sum % 10;
                a[pos - 1] += sum / 10;
            }
        }
        //
        string ret;
        int index = 0;
        // 去除前导0,此时小坐标存放高位数据,大坐标存放低位数据
        while(len1 + len2 - index > 1 && a[index] == 0){
            index++;
        }
        // 正着取数据
        while(index < len1 + len2){
            ret += a[index] + '0';
            index++;
        }
        
        return ret;
    }
};
class Solution {
public:
    string multiply(string num1, string num2) {
        int len1 = num1.size();
        int len2 = num2.size();
        // 结果的位数范围[len1+len2-1, len1+len2];
        int a[len1 + len2];
        memset(a, 0, sizeof(int) * (len1 + len2));
        for(int i = len1 - 1; i >= 0; --i){
            for(int j = len2 - 1; j >= 0; --j){
	            // 倒着存数据
                int pos = len1 + len2 - i - j - 2;
                int sum = (num1[i] - '0') * (num2[j] - '0') + a[pos];
                a[pos] = sum % 10;
                a[pos + 1] += sum /10;
            }
        }
        //
        string ret;
        int index = len1 + len2 - 1;
        // 去除无效的0,此时小坐标存放低位数据,大坐标存放高位数据
        while(index > 0 && a[index] == 0){
            index--;
        }
        // 倒着取数据
        for(int i = index; i >= 0; --i){
            ret += a[i] + '0';
        }
        //
        return ret;
    }
};

T h e The The E n d End End

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/109784.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Acrobat Pro DC 2023 PDF编辑器 for Mac

Acrobat Pro DC是一款由Adobe开发的专业级PDF编辑和管理软件。作为PDF行业的标准工具&#xff0c;它提供了广泛的功能和工具&#xff0c;适用于个人用户、企业和专业人士。 Acrobat Pro DC具备丰富的编辑功能&#xff0c;可以对PDF文件进行文本编辑、图像编辑和页面重排等操作。…

订水商城H5实战教程-05权限控制

目录 1 判断用户是否登录2 创建事件流3 获取不到Userid的问题4 权限控制整体效果 我们上一篇讲解了用户注册的功能&#xff0c;当用户注册完毕的时候再次打开小程序的时候就需要验证权限。权限分为两类&#xff0c;第一类是判断用户是否注册&#xff0c;第二类是当前用户具备什…

Linux启动之uboot分析

Linux启动之uboot分析 uboot是什么&#xff1f;一、补充存储器概念1.存储器种类1.norflash - 是非易失性存储器&#xff08;也就是掉电保存&#xff09;2.nandflash - 是非易失性存储器&#xff08;也就是掉电保存&#xff09;3.SRAM - 静态随机访问存储器 - Static Random Acc…

什么是鉴权?一篇文章带你了解postman的多种方式

一、什么是鉴权&#xff1f; 鉴权也就是身份认证&#xff0c;就是验证您是否有权限从服务器访问或操作相关数据。发送请求时&#xff0c;通常必须包含相应的检验参数以确保请求具有访问权限并返回所需数据。通俗的讲就是一个门禁&#xff0c;您想要进入室内&#xff0c;必须通…

MySQL(3):基本的 SELECT 语句

SQL 语言 SQL&#xff08;Structured Query Language&#xff0c;结构化查询语言&#xff09;是使用关系模型的数据库应用语言&#xff0c; 与数据直接打交道 。 SQL 有两个重要的标准&#xff0c;分别是 SQL92 和 SQL99&#xff0c;它们分别代表了 92 年和 99 年颁布的 SQL 标…

一体化模型图像去雨+图像去噪+图像去模糊(图像处理-图像复原-代码+部署运行教程)

本文主要讲述了一体化模型进行去噪、去雨、去模糊&#xff0c;也就是说&#xff0c;一个模型就可以完成上述三个任务。实现了良好的图像复原功能&#xff01; 先来看一下美女复原.jpg 具体的&#xff1a; 在图像恢复任务中&#xff0c;需要在恢复图像的过程中保持空间细节…

windows应用软件扫描报告 不告谱 要钱

chatGPT开路&#xff0c;帮找。 当你想要查找Windows软件的漏洞而不涉及查看源代码时&#xff0c;你可以使用一些专门设计用于扫描漏洞的工具。这些工具通常会检查已安装的软件和操作系统的漏洞&#xff0c;并提供建议或修补程序。以下是一些可以用于查找Windows软件漏洞的工具…

SQL优化(慢查询优化方法)正确使用数据库索引

文章目录 (一) 建立索引的正确姿势1 &#xff09;索引不要包含选择性过低字段2&#xff09; 选择性高的字段前置或者单独建立索引3&#xff09;尽量使用覆盖索引 (二) 使用索引的正确姿势1&#xff09; 最左匹配截断2&#xff09; 隐式转换3&#xff09; in order by 导致排序失…

R2R 的一些小tip

批次间控制器(Run-to-run Controller)&#xff0c;以应对高混合生产的挑战。将最优配方参数与各种工业特征相关联的模型是根据历史数据离线训练的。预测的最优配方参数在线用于调整工艺条件。 批次控制(R2R control)是一种先进的工艺控制技术&#xff0c;可在运行(如批次或晶圆…

Matlab | 基于二次谱提取地震数据的地震子波

本文通过地震数据二次谱求取地震子波谱&#xff0c;具体方法如下&#xff1a; MATLAB代码实现如下&#xff1a; function w SndSpecExtWavelet(x, M) % 功能&#xff1a;基于二次谱提取输入地震数据data的地震子波wavelet % Extracting Wavelet from Input Seismic Dat…

Flutter 使用 GetX 中遇到的问题

创建了控制器&#xff0c;但是在别的页面中&#xff0c;无法引用控制器里面的某些变量 如下图&#xff1a;后来发现&#xff0c;是命名的问题&#xff0c; 如果是以 _ 下划线开头的变量&#xff0c;那么就无法被引用

测开(性能测试---LoadRunner)

目录 一、LoadRunner的安装 二、Loadrunner的基本概念 三、开发测试脚本——VUG 3.1 脚本录制 3.2 脚本加强 四、设计场景——Controller LoadRunner是一款开源桌面应用软件&#xff0c;可用来模拟用户负载完成性能测试工作&#xff0c;LoadRunner的功能在版本不断升级的…

SDP协议分析

目录 SDP的结构SDP语法必需字段可选字段字段顺序子字段 3.SDP例子 1. SDP的结构 SDP&#xff08;Session Description Protocol&#xff09;完全是⼀种会话描述格式&#xff0c;它不属于传输协议&#xff0c;它只使⽤于适当的传输协议&#xff0c;包括会话通知协议&#xf…

ERROR: There can be only one Game target per project.

UATHelper: Packaging (Windows (64-bit)): ERROR: There can be only one Game target per project. D:\dock\Intermediate\Source 把旧的文件删去 一般会出现在更改项目名称后 感谢 There can be only one Game target per project - Development Discussion / Content C…

关于Spring和SpringBoot中对配置文件的读取

Spring读取xml文件 具体流程见网址Spring源码分析2 — spring XML配置文件的解析流程 - 知乎 (zhihu.com) 我这里只做一下总结和自己的理解&#xff1a; &#xff08;1&#xff09;通过getConfigLocations方法, 从web.xml文件中读取配置文件地址&#xff0c;如果web.xml中读取…

使用 jdbc 技术升级水果库存系统(后端最终版本,不包含前端)

1、配置依赖 <dependencies><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.10</version></dependency><dependency><groupId>junit</groupId><…

智能工厂解决方案

智能工厂解决方案&#xff1a;生产工单 智能工厂解决方案&#xff1a;物流中转 样品单-4.2寸 工单任务卡-4.2寸 工单流转卡-4.2寸 生产配送卡-4.2寸 工序参数卡-7.5寸 生产拣配单-7.5寸 仓库24代-参数 接收路由器发送的数据信息并解析&#xff0c;做出相应的指示&#…

图片去除水印文字怎么去除?这几个方法快来收藏

图片怎么去除水印文字&#xff1f;现在嘛&#xff0c;图片已经成了我们生活和工作里必不可少的一部分&#xff0c;可是有时候看图的时候&#xff0c;总会碰到一些带水印的图片&#xff0c;这些水印总是搞得图片看起来不那么爽&#xff0c;所以很多人都想知道图片怎么去除水印文…

如何改善设备综合效率(OEE)并提高工厂的生产力

在现代制造业中&#xff0c;提高设备综合效率&#xff08;Overall Equipment Efficiency&#xff0c;OEE&#xff09;是企业追求高效生产和优化生产能力的重要目标之一。OEE是一个关键的绩效指标&#xff0c;可以帮助企业评估设备的利用效率、生产效率和质量水平。本文将从三个…

[UDS] --- RoutineCommunicationControl 0x31

1 0x31功能描述 client端使用RoutineControl服务执行定义的步骤序列并获取任何相关结果。该服务具有很大的灵活性&#xff0c;典型的用法包括擦除内存&#xff0c;复位或学习自适应数据&#xff0c;运行自检&#xff0c;覆盖正常服务器控制策略以及控制服务器值随时间变化等功…
最新文章