Leetcode 43. 字符串相乘 中等

news2024/9/27 9:29:02

题目 - 点击直达

  • 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.coloradmin.cn/o/1151465.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

react中的useState和useImmer的用法

文章目录 一、useState1. 更新基本类型数据2. 更新对象3. 更新嵌套对象4. 更新数组5.更新数组对象 二、Immer1. 什么是Immer2. 使用use-immer更新嵌套对象3. 使用useImmer更新数组内部的对象 一、useState react中文官网教程 1. 更新基本类型数据 在函数式组件中&#xff0c…

【多线程相关其二】进程与线程

进程vs线程 进程&#xff08;process&#xff09;指的是正在运行的程序的实例&#xff0c;即an instance of a computer that is being executed。用拆字法理解就是&#xff1a;进行中的程序。程序是一个没有生命的实体&#xff0c;只有处理器执行它的时候才能成为一个活动的实…

macOS 创建Flutter项目

参考在 macOS 上安装和配置 Flutter 开发环境 - Flutter 中文文档 - Flutter 中文开发者网站 - Flutter 这个文档&#xff0c;配置好flutter的环境 编辑器可以选择vscode或者IDEA。 我这里以IDEA为例 打开 IDE 并选中 New Flutter Project。 选择 Flutter&#xff0c;验证 F…

长图切图怎么切

用PS的切片工具 切片工具——基于参考线的切片——ctrl&#xff0b;shift&#xff0b;s 过长的图片怎么切 ctrl&#xff0b;alt&#xff0b;i 查看图片的长宽看图片的长宽来切成两个板块&#xff08;尽量中间切成两半&#xff09;用选区工具选中下半部分的区域——在选完时不…

电脑系统d3dcompiler_47.dll丢失问题,多种详细解决方法推荐

d3dcompiler_47.dll是Direct3D编译器组件的一部分&#xff0c;它是Microsoft DirectX的一部分。DirectX是一套由微软开发的多媒体编程接口&#xff0c;用于游戏和多媒体应用的开发。d3dcompiler_47.dll文件主要用于对DirectX编译器的调用&#xff0c;它包含了Direct3D着色器编译…

【C++】map 和 set 的使用

目录 C中的键值对 关联式容器 set、multiset map、multimap STL的容器分为两类&#xff1a;序列是容器、关联式容器&#xff1b;序列式容器是线性的数据结构&#xff0c;只有存储元素的功能&#xff0c;且像vector、list等还可以指定插入位置&#xff1b;而关联式容器底层底…

C++核心编程之---类和对象---C++对象模型和this指针

目录 一、成员变量和成员函数分开存储 二、this指针 三、空指针访问成员函数 四、const修饰成员函数 常函数&#xff1a; 常对象&#xff1a; 一、成员变量和成员函数分开存储 在C中&#xff0c;类内的成员变量和成员分开存储 只有非静态成员变量才属于类的对象上 示例&…

计算机基础知识42

标签的分类和嵌套 1. 单标签&#xff1a; img br hr # <img /> 2. 双标签&#xff1a; a h p div # <a></a> 3. 按照标签属性分类&#xff1a; 块儿标签&#xff1a; 自己独自占一行 # h1-h6 p div 行内(内联)…

2023高德地图poi资源下载

全国8千万地图poi地图数据&#xff1a;含名称、地址、电话、省份、城市、区县、经纬度、电话等信息

笔记47:FCN网络的Pytorch实现

本地笔记地址&#xff1a;D:\work_file\DeepLearning_Learning\03_个人笔记\1.语义分割任务\Pytorch中FCN的实现 a a a

数据结构——线性表②(链表)

《数据结构——线性表①&#xff08;顺序表&#xff09;》一文中已经讲了线性表顺序存储–顺序表相关内容&#xff0c; 这篇文章一起来学习 线性表的链式存储–链表↓↓↓↓↓ 一、链表的定义 线性表的链式存储称为链表&#xff0c;那什么是链式存储呢 其实理解起来就和火车差…

Jetpack:023-Jetpack中的事件二

文章目录 1. 知识回顾2. 使用方法2.1 单击事件2.2 双击事件2.3 长按事件2.4 滑动事件 3. 示例代码4. 内容总结 我们在上一章回中介绍了 Jetpack中事件相关的内容&#xff0c;本章回中继续介绍这方面的内容。闲话休提&#xff0c;让我们一起Talk Android Jetpack吧&#xff01;…

【Java数据结构重点知识】第一节:认识数据结构与算法、集合框架

一&#xff1a;数据结构与算法 1.数据结构 数据结构是计算机存储、组织数据的方式&#xff0c;指相互之间存在一种或多种特定关系的数据元素的集合 2.算法 算法就是定义良好的计算过程。他取一个或一组的值为输入&#xff0c;并产生一个或一组作为输出。简单来说就是一系列的…

Linux】centos安装配置及远程连接工具的使用

【Linux】centos安装配置及远程连接工具的使用 1.使用vmware创建虚拟机&#xff0c;因为过程比较简单就没有截图了&#xff0c;根据下面步骤来就行。2.网络配置3.MobaXterm连接CentOS1.new session2.点击ssh&#xff0c;输入虚拟机的IP地址即可 4.进行阿里云换源1.进入2.下载wg…

AMD:抢占AI芯片宝座

来源&#xff1a;猛兽财经 作者&#xff1a;猛兽财经 总结&#xff1a; &#xff08;1&#xff09;AMD受益于AI芯片的出口限制&#xff0c;使其能够获得更多的中国市场份额&#xff0c;并增强其在AI芯片市场的地位。 &#xff08;2&#xff09;AMD的处理器&#xff0c;特别是E…

ctfshow-web入门命令执行29-36

29 源代码给了禁用flag 使用tac、nl ?cecho nl f*; ?cecho tac f*; 30 多禁用了system和php 和上题区别不大&#xff0c;使用上一题命令就能解 ?cecho nl f*; ?cecho tac f*; 31 禁用了空格使用%09代替 ?cecho%09tac%09f*; 32 禁用了echo 使用php伪协议 ?cinclud…

从零开始学习搭建量化平台笔记

从零开始学习搭建量化平台笔记 本笔记由纯新手小白开发学习记录&#xff0c;欢迎大佬请教指点留言&#xff0c;有空的话还可以认识一下&#xff0c;来上海请您喝咖啡~~ 2023/10/30&#xff1a;上份工作辞职并休息了几个月后&#xff0c;打算开始找个关于量化投资相关的工作。面…

云原生之使用Docker部署slash书签共享平台

云原生之使用Docker部署slash书签共享平台 一、slash介绍1.1 slash简介1.2 slash特点 二、本地环境介绍2.1 本地环境规划2.2 本次实践介绍 三、本地环境检查3.1 检查Docker服务状态3.2 检查Docker版本3.3 检查docker compose 版本 四、下载slash镜像五、部署slash书签共享平台5…

2模块和包的一些总结:导入库和模块

感觉这块好零散呀&#xff0c;应该怎么去写呢&#xff1f;截图吧 1、导入多个模块的方法 #导入多个包有几种办法 # 1.用点号 # 2.用逗号import p1.Tool import p1.sub_p.sub_xxxprint(p1.Tool.num) print(p1.sub_p.sub_xxx.num)import p1.Tool,p1.sub_p.sub_xxx print(p1.Tool…

基于纵横交叉算法的无人机航迹规划-附代码

基于纵横交叉算法的无人机航迹规划 文章目录 基于纵横交叉算法的无人机航迹规划1.纵横交叉搜索算法2.无人机飞行环境建模3.无人机航迹规划建模4.实验结果4.1地图创建4.2 航迹规划 5.参考文献6.Matlab代码 摘要&#xff1a;本文主要介绍利用纵横交叉算法来优化无人机航迹规划。 …