算法:字符串相关

目录

题目一:最长公共前缀

题目二:最长回文子串

题目三:二进制求和

题目四:字符串相乘


题目一:最长公共前缀

编写一个函数来查找字符串数组中的最长公共前缀

如果不存在公共前缀,返回空字符串 ""

示例 1:

输入:strs = ["flower","flow","flight"]
输出:"fl"

示例 2:

输入:strs = ["dog","racecar","car"]
输出:""
解释:输入不存在公共前缀。

提示:

  • 1 <= strs.length <= 200
  • 0 <= strs[i].length <= 200
  • strs[i] 仅由小写英文字母组成

解法一:两两比较

解法一就是两两比较的策略,先进行前两个字符串的比较,比较完后,将前两个字符串的公共前缀再与第三个字符串比较,从而得到前三个字符串的公共前缀,以此类推

代码如下:

class Solution 
{
public:
    string findCommon(string& s1, string& s2)
    {
        int i = 0;
        //i有可能会出现越界的情况,所以i小于s1s2长度时再循环判断
        while(i < min(s1.size(), s2.size()) && s1[i] == s2[i])
            i++;
        return s1.substr(0, i);
    }

    string longestCommonPrefix(vector<string>& strs) 
    {
        int n = strs.size();
        //same字符串就是存储最长公共前缀的字符串
        string same = strs[0];
        for(int i = 1; i < n; i++)
            same = findCommon(same, strs[i]);
        return same;
    }
};

解法二:统一比较

统一比较也就是一次性将所有字符串的同一位置作比较,判断是否该位置相同,直到出现不同的字符时为止

这里会出现越界的情况,出现越界说明某一个字符串已经结束了,那么也就可以终止比较了

代码如下:

class Solution 
{
public:
    string longestCommonPrefix(vector<string>& strs) 
    {
        int i = 0;
        //以第一个字符串为基准,与其他所有字符串做比较
        for(i = 0; i < strs[0].size(); i++)
        {
            //ch表示第一个字符串当前循环到的字符
            char ch = strs[0][i];
            //循环strs中其余的字符串,其余字符串的i位置字符与ch做比较
            for(int j = 1; j < strs.size(); j++)
            {  
                //如果i大于当前字符串的长度,说明当前字符串已经没有元素了
                if(i > strs[j].size() || strs[j][i] != ch)
                    return strs[0].substr(0, i);
            }
        }
        return strs[0];
    }
};

题目二:最长回文子串

给你一个字符串 s,找到 s 中最长的 回文子串

示例 1:

输入:s = "babad"
输出:"bab"
解释:"aba" 同样是符合题意的答案。

示例 2:

输入:s = "cbbd"
输出:"bb"

普通的暴力枚举算法,设置两个指针,一个 i 一个 j ,固定 i ,向后移动 j ,每次移动 j 都需要判断 i 和 j 之间的字符串是否是回文子串,此时移动 j 和判断 i、j 之间是否是回文子串,这里的时间复杂度是O(N^2),又因为外面嵌套着一层 i ,用于遍历整个字符串,所以整个暴力枚举的时间复杂度是非常高的,达到了O(N^3),下面看优化后的中心扩展算法:

解法:中心扩展算法

中心扩展算法就是:

①固定一个中心点
②从中心点开始,向两边扩展(奇数和偶数长度都需要考虑到)

也就是每次固定一个中心点 i,每次向 i 的左边和右边扩展,判断是否是回文串,这种算法遍历 i 时间复杂度是O(N),嵌套的向 i 的左边和右边扩展,时间复杂度也是O(N),所以最终是O(N^2),会比上面所说的暴力解法,优化非常多

需要注意的就是中心扩展算法的第二点,需要考虑奇数和偶数,因为奇数是将left和right指针,从 i 位置开始一左一右移动,而偶数需要left在 i 位置,right在 i + 1位置,然后再一左一右移动

需要注意代码中的长度是 right - left - 1,因为当前 left 和 right 指向元素如果相同,需要将left--,right++,此时如果不相同就退出循环,所以 left 和 right 都比回文串多移动了一个位置,所以长度才是 right - left - 1 计算的,具体见下图:

如上图所示,left和right指向当前时退出循环,所以回文子串aa的长度就是:
right - left - 1 = 3 - 0 - 1 = 2


代码如下:

class Solution 
{
public:
    string longestPalindrome(string s) 
    {
        if(s.size() == 1) return s;
        int n = s.size(), begin = 0, size = 0;
        for(int i = 0; i < n; i++)
        {
            //先做奇数长度的扩展
            int left = i, right = i;
            //left和right符合条件,且指向元素相等再进入循环
            while(left >= 0 && right < n && s[left] == s[right])
            {
                --left;
                ++right;
            }
            //如果长度更大,更新begin与size
            if((right - left - 1) > size)
            {
                size = right - left - 1;
                begin = left + 1;
            }
            //再做偶数长度的扩展
            left = i, right = i + 1;
            //left和right符合条件,且指向元素相等再进入循环
            while(left >= 0 && right < n && s[left] == s[right])
            {
                --left;
                ++right;
            }
            //如果长度更大,更新begin与size
            if((right - left - 1) > size)
            {
                size = right - left - 1;
                begin = left + 1;
            }            
        }
        return s.substr(begin, size);
    }
};

题目三:二进制求和

给你两个二进制字符串 a 和 b ,以二进制字符串的形式返回它们的和。

示例 1:

输入:a = "11", b = "1"
输出:"100"

示例 2:

输入:a = "1010", b = "1011"
输出:"10101"

这道题就是计算高精度的加法,进行一个模拟运算,模拟列竖式计算的过程

需要设定两个指针cur1和cur2,分别指向两个字符串,再设定一个变量t ,表示进位

代码如下:

class Solution 
{
public:
    string addBinary(string a, string b) 
    {
        //t表示相加后的进位
        int t = 0;
        string ret;
        int cur1 = a.size()-1, cur2 = b.size()-1;
        //cur1或cur2 >= 0表示字符串没遍历完,t>0表示还剩一个进位
        while(cur1 >= 0 || cur2 >= 0 || t)
        {
            if(cur1 >= 0) t += a[cur1--] - '0';  
            if(cur2 >= 0) t += b[cur2--] - '0';
            ret += to_string(t % 2);
            t /= 2;
        }
        //从后向前加的,刚好反过来了,需要逆置
        reverse(ret.begin(), ret.end());
        return ret;
    }
};

题目四:字符串相乘

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

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

示例 1:

输入: num1 = "2", num2 = "3"
输出: "6"

示例 2:

输入: num1 = "123", num2 = "456"
输出: "56088"

解法一:模拟竖式运算

就是数学上,乘法列的竖式,这是最容易想到的方法

如下所示:

我们可以理解为,下面的456的每一位分别乘上面的123,再相加,有三点细节:

①高位相乘需要补0,因为738和615相加时错了一位,可以理解为 738 + 6150
②处理前导0,可能出现123 × 0 的情况,这时答案是000,需要处理一下
③注意计算结果的顺序,因为计算时是逆序计算的,乘法都是从最后一位开始计算的

但是这种方法并不好写代码,我们需要借助这种方法来优化一下

解法二:对解法一优化

无进位相乘再相加,最后一步再处理进位:

即相乘时不管是多少,都不进位,最后加完后再进位

同样,在开始计算时,先逆序,这里由于相乘后可能是两位数,所以就不能使用string表示了,可以采用一个数组存储

由于逆序了,所以123对应的的下标是2,1,0,456对应的下标也是2,1,0

有一个非常好用的规律:i 和 j 下标的数相乘,结果恰好放在数组第 i + j 位上

①定义一个长度是 m + n - 1 数组tmp(m和n对应两个相乘数字的长度)
正在相乘的两个数字的下标分别是 i,j,将计算的结果放在数组的第 i + j 位上
②最后加完以后,需要处理进位
③处理前置0

代码如下:

class Solution 
{
public:
    string multiply(string num1, string num2) 
    {
        //先逆序两个字符串
        reverse(num1.begin(), num1.end());
        reverse(num2.begin(), num2.end());
        //定义一个数组tmp
        int m = num1.size(), n = num2.size();
        vector<int> tmp(m + n - 1);
        //无进位相乘然后相加
        for(int i = 0; i < m; i++)
            for(int j = 0; j < n; j++)
                tmp[i + j] += (num1[i] - '0') * (num2[j] - '0');
        //处理进位
        string ret;
        int t = 0, cur = 0;
        while(cur < m + n - 1 || t != 0)
        {
            if(cur < m + n - 1) t += tmp[cur++];
            ret += to_string(t % 10);
            t /= 10;
        }
        if(t) ret += to_string(t);
        //处理前置0
        while(ret.back() == '0' && ret.size() > 1) ret.pop_back();
        reverse(ret.begin(), ret.end());

        return ret;
    }
};

字符串相关的题目到此结束

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

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

相关文章

mysql判断时间段是否重合

mysql判断时间段是否重合 SELECT CASE WHEN t1.start_time < t2.end_time AND t1.end_time > t2.start_time THEN ‘重合’ ELSE ‘不重合’ END AS result FROM table_name t1, table_name t2 WHERE t1.id <> t2.id;

产品经理-交互设计动手实践(11)

业内有很多画交互的工具&#xff0c;这里不过多介绍&#xff0c;互联网公司最常用的工具是Axure,墨刀,蓝湖,小瀑 它是一个专业的快速原型设计工具&#xff0c;使用它能够快速创建线框图、流程图、原型和规格说明文档。 它能快速、高效地创建原型&#xff0c;同时支持多人协作设…

不想成为失业大军,就要学习六西格玛?

最近&#xff0c;优思学院收到一封邮件&#xff0c;这封邮件的发送者是一位完成了我们六西格玛绿带课程的学生。 他的公司裡有20%的工程师被裁员&#xff0c;但值得注意的是&#xff0c;留下来的工程师中有70%人竟然都持有六西格玛绿带或黑带证书。 他的公司不仅希望利用这些…

科普文:深入理解Mybatis

概叙 (1) JDBC JDBC(Java Data Base Connection,java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成.JDBC提供了一种基准,据此可以构建更高级的工具和接口,使数据库开发人员能够编写数据库应用程序。 优点…

React文档内网搭建

React文档内网搭建流程 官网地址 官网中文地址 通过官网我们可以找到React的github存储库 ReactGitHub 在介绍中可以找到对应的文档存储库 React文档存储库 此存储库是英文文档地址,我们通过中文文档地址以及该存储库作者目录下找到中文存储库 React文档中文存储库 下载…

JavaSE语法 | 初识Java!!!

初识Java 一、Java开发环境二、初步认识Java的main方法2.1 main方法的实现2.2 运行Java程序 三、注释四、标识符五、关键字 一、Java开发环境 IDEA版本&#xff1a;IntelliJ IDEA Community Edition 2022.3.3 JDK17 Windows 11 二、初步认识Java的main方法 2.1 main方法的实…

C语言入门-1.数据的类型、数据的输入输出

数据类型常量变量&#xff08;整型-浮点-字符&#xff09; 数据类型 基本类型 整型int 符号常量 定义一个整形变量时要使用关键字int #include <stdio.h> //符号常量练习 #define PI 3 2 int main() {int i PI * 2;printf("i%d\n",i);return 0; } //7 …

解密 AI 客服:LangChain+ChatGPT 打造智能客服新时代

你需要了解 ChatGPT ChatGPT 是 OpenAI 开发的一种基于人工智能技术的自然语言处理模型。它可以通过对大量文本数据进行训练&#xff0c;自动生成高质量的回答和对话。ChatGPT 具有高效、准确、自然的特点&#xff0c;可以帮助人们更加高效地处理信息和交流。 ChatGPT 有很多…

QT TCP多线程网络通信

学习目标&#xff1a; TCP网络通信编程 学习前置环境 运行环境:qt creator 4.12 QT TCP网络通信编程-CSDN博客 Qt 线程 QThread类详解-CSDN博客 学习内容 使用多线程技术实现服务端计数器 核心代码 客户端 客户端&#xff1a;负责连接服务端&#xff0c;每次连接次数1。…

启动tomcat时提示The JRE_HOME environment variable is not defined correctly

我的情况是在已经安装过jdk后&#xff0c;启动tomcat时出现以下问题 原因是环境变量配置不正确导致的 首先确认一下jre的实际安装路径 然后修改环境变量配置文件 vim /etc/profile 添加以下内容&#xff0c;JRE_HOME为实际jre的路径 然后保存退出 让文件生效一下 source…

Docker-搭建部署Jenkins(保姆篇)

文章目录 Jenkins部署拉取镜像启动容器查看初始密码关闭CSRF Jenkins页面使用解决插件下载缓慢访问jenkins页面推荐插件安装创建一个管理员账号实例配置页面展示 更多相关内容可查看 Jenkins部署 拉取镜像 如果想拉取对应版本请指明版本号 docker pull jenkins/jenkins:lts-…

数据分析入门指南:表结构数据(三)

在数字化转型的浪潮中&#xff0c;表结构数据作为企业决策支持系统的核心要素&#xff0c;其重要性日益凸显。本文深入剖析了表结构数据的本质特征、高效处理策略&#xff0c;并探讨了其在现代商业智能环境中的广泛应用&#xff0c;旨在为数据分析师与决策者提供前沿洞察与实战…

电脑屏幕亮度怎么调?3个技巧,指尖轻松调控明亮度

你是否曾因为屏幕亮度的不合适而感到眼睛疲劳&#xff1f;是否曾在深夜加班时&#xff0c;被电脑屏幕刺眼的亮度搅得心烦意乱&#xff1f;电脑屏幕亮度怎么调呢&#xff1f;本文将为你介绍3个简便易行的技巧&#xff0c;让指尖轻松掌控屏幕亮度&#xff0c;享受舒适的观看体验。…

前端vue 实现取色板 的选择

大概就是这样的 一般的web端框架 都有自带的 的 比如 ant-design t-design 等 前端框架 都是带有这个的 如果遇到没有的我们可以自己尝试开发一下 简单 的 肯定比不上人家的 但是能用 能看 说的过去 我直接上代码了 其实这个取色板 就是一个input type 是color 的input …

Vue组件通信props和$emit用法

父传子&#xff0c;通过props 子传父&#xff0c;通过$emit App.vue <template><div class"app" style"border: 3px solid #000; margin: 10px">我是APP组件<!-- 1.给组件标签&#xff0c;添加属性方式 赋值 --><!-- 添加属性传值 …

untiy 在菜单栏添加自定义按钮 点击按钮弹出一个Unity窗口,并在窗口里添加属性

using System.Collections.Generic; using UnityEditor; using UnityEngine; using UnityEngine.Rendering.PostProcessing;public class AutoGenerateWindow : EditorWindow //这是定义一个窗口 {public string subjecttName "科目名字";//科目的名字public GameOb…

补光灯LED照明 2.7V4.2V5V升60V80V100V升压恒流芯片IC-H6902B

H6902B升压恒流芯片IC确实是一款为LED照明应用设计的稳定且可靠的解决方案。这款芯片具有以下几个显著特点&#xff1a; 高效率&#xff1a;效率高达95%以上&#xff0c;这意味着在驱动LED灯时&#xff0c;电源到LED的能量转换效率非常高&#xff0c;减少了能量损失&#xff0…

抖音本地生活服务商怎么申请?附详细教程!

随着本地生活的发展潜力和行业前景的不断展现&#xff0c;本地生活服务商也逐渐成为了一大热门职业。在此背景下&#xff0c;作为拥有约8亿日活用户的抖音成为了人们选择平台时的优先考虑对象&#xff0c;而以抖音本地生活服务商怎么申请为代表的相关问题也因此在多个创业者群中…

雪花算法改造失败导致ID重复问题分享

背景 雪花算法是分布式应用中应用比较多的 ID 生成算法&#xff0c;某项目中使用该算法生成ID&#xff0c;近期被反馈算法生成的 ID 存在重复的情况&#xff0c;排了一天&#xff0c;终于找到问题根源了。 本文将总结这个 Bug &#xff0c;顺便温故一下雪花算法及改造雪花算法…

mes系统在新材料行业中的应用价值

万界星空科技新材料MES系统是针对新材料制造行业的特定需求而设计的制造执行系统&#xff0c;它集成了生产计划、过程监控、质量管理、设备管理、库存管理等多个功能模块&#xff0c;以支持新材料生产的高效、稳定和可控。以下是新材料MES系统的具体功能介绍&#xff1a; 一、生…