算法_字符串专题---持续更新

文章目录

前言

本文将会向你介绍有关字符串的相关题目:最长公共前缀、最长回文子串、二进制求和、字符串相乘。本篇并不是介绍字符串相关的算法,只是将题目要求为字符串类型的归类

最长公共前缀

https://leetcode.cn/problems/longest-common-prefix/description/

题目要求

题目解析

题目要求找到最长公共前缀,我们很简单地就能想到将字符串中的字符一一比较,返回最长公共前缀,这里采用的是字符串两两比较,先拿第一个字符串与第二个字符串比较,再拿它们的最长公共前缀与第三个字符串比较,最后就能得到最长公共前缀

代码如下

cpp 复制代码
string findCommon(string& s1, string& s2)
{
    int i = 0;
    //注意条件,比较两个字符串,最短的字符串结束就结束了
    while(i < min(s1.size(), s2.size()) && s1[i] == s2[i]) 
    {
        i++;
    }
    return s1.substr(0, i);
}
class Solution {
public:
    string longestCommonPrefix(vector<string>& strs)
    {
        string ret = strs[0];
        for(int i = 1; i < strs.size(); i++)
        {
            ret = findCommon(ret, strs[i]);
        }
        return ret;
    }
};

最长回文子串

https://leetcode.cn/problems/longest-palindromic-substring/

题目要求

题目解析

给一个字符串,要求出字符串中最长的回文子串,即需要在一个字符串中找到中间对称的子串,aba,bab都是关于中间对称,那么我们可以对所有的可能为中点的点遍历一遍,这样才能找出最长的,这里采用中心扩展算法,即遍历每个点(每次把该点当作中点),从该点开始向左向右进行移动,如果left[i] = right[i],则继续向左向右移动,直到不相同位置,那么就可以找到以某个点为中心对称的字符串 注意点:分奇偶
当出现类似回文子串b a b这种格式,是需要将left = right = i(i:遍历的每个点),即子串字符数为奇数情况 当出现类似回文串b b这种格式,是需要将left = i,right = i + 1 即子串字符数为偶数情况

代码如下

cpp 复制代码
class Solution {
public:
    string longestPalindrome(string s) 
    {
        int n = s.size();
        int len = 0;    //最长回文串长度
        int begin = 0;  //回文串的起始位置
        //遍历所有可能为中点的点
        for(int i = 0; i < n; i++)
        {
            //字符串为奇数个字符
            int left = i, right = i;
            while(left >= 0 && right <= n && s[left] == s[right])
            {
                left--;
                right++;
            }
            if(right - left - 1 > len)
            {
                len = right - left - 1;
                begin = left + 1;
            }
            //字符串为偶数个字符
            left = i, right = i + 1;
            while(left >= 0 && right <= n && s[left] == s[right])
            {
                left--;
                right++;
            }
            if(right - left - 1 > len)
            {
                len = right - left - 1;
                begin = left + 1;
            }
        }
        return s.substr(begin, len);
    }
};

二进制求和

https://leetcode.cn/problems/add-binary/

题目要求

题目解析

给两个字符串,按照二进制加法相加,我们很自然地能想到遍历每个字符,然后按照二进制相加,模拟加法过程即可

注意点一:字符串模拟加法
在正常加法中,我们都是从低位,即图中下标为3的位置相加直到加到高位,其中还包含低位向高位的进位,因此模拟过程中也需要把进位给模拟出来,因此我们必须也要从下标为3的位置字符开始相加 也可以看看另一道类似解法的题

两数相加,这在篇文章链表专题中也提到过

注意点二:结束条件
当其中一个字符串结束,都不能作为结束条件,而且当两个字符串都遍历完了,可能进位不为0,也不能结束 ## 代码如下

cpp 复制代码
class Solution {
public:
    string addBinary(string a, string b) 
    {
        int t = 0; //进位
        string ret;
        int cur1 = a.size() - 1;
        int cur2 = b.size() - 1;
        while(cur1 >= 0 || cur2 >= 0 || t > 0)
        {
            if(cur1 >= 0)
            {
                t += a[cur1] - '0';
                cur1--;
            }
            if(cur2 >= 0)
            {
                t += b[cur2] - '0';
                cur2--;
            }
            ret += t % 2 + '0';
            t/=2;
        }
        reverse(ret.begin(), ret.end());
        return ret;
    }
};

字符串相乘

https://leetcode.cn/problems/multiply-strings/

题目要求

题目解析

这道题容易想到的解法就是以其中一个字符串每一位去乘以另一个字符串,然后将每次相乘的结果再相加,如下图所示

但这种解法并不好写,因此将会介绍另一种不好想到,但是好写的解法

解法二

无进位相乘再相加,再处理进位

由于给定字符串下标的顺序与我们实际乘法+进位的顺序相反,所以我们先将给定字符串逆序一下,注意以后碰到带有进位类似的题目,最好也是先逆序一下

一、模拟乘法相加
直接将两个字符串中的字符 - '0'相乘再相加即可,注意符号+=

cpp 复制代码
        for (int i = 0; i < sz1; i++)
        {
            for (int j = 0; j < sz2; j++)
            {
                tmp[i + j] += ((num1[i] - '0') * (num2[j] - '0'));
            }
        }

二、模拟进位操作
先用t保存相乘再相加的结果,将个位上的数留下,十位上的数进位

cpp 复制代码
        //进位操作
        string ret;
        int t = 0, cur = 0; //进位
        while(cur < sz1 + sz2 - 1 || t != 0)
        {
            if(cur < sz1 + sz2 - 1) t += tmp[cur++];
            ret += t % 10 + '0';
            t /= 10;
        }

三、去掉前导0
如果123 乘 0 按照我们以上的模拟乘法,将会得出000,因此需要把前两个0给去掉

cpp 复制代码
        while(ret.size() > 1 && ret.back() == '0') ret.pop_back();

注意:当进位不为0的时候也不能结束循环,因为可能存在两个字符串最后一位为:3 + 7,进位为 1

最后逆序保存结果的字符串即可

代码如下

cpp 复制代码
class Solution {
public:
    string multiply(string num1, string num2)
    {
        reverse(num1.begin(), num1.end());
        reverse(num2.begin(), num2.end());
        int sz1 = num1.size();
        int sz2 = num2.size();
        vector<int> tmp(sz1 + sz2 - 1);   //无进位相乘再相加后的数组
        for (int i = 0; i < sz1; i++)
        {
            for (int j = 0; j < sz2; j++)
            {
                tmp[i + j] += ((num1[i] - '0') * (num2[j] - '0'));
            }
        }
        //进位操作
        string ret;
        int t = 0, cur = 0; //进位
        while(cur < sz1 + sz2 - 1 || t != 0)
        {
            if(cur < sz1 + sz2 - 1) t += tmp[cur++];
            ret += t % 10 + '0';
            t /= 10;
        }
        //去掉前导零
        while(ret.size() > 1 && ret.back() == '0') ret.pop_back();
        reverse(ret.begin(), ret.end());
        return ret;
    }
};
相关推荐
weixin_515033938 分钟前
ccfcsp-202006(4、5)
c++·算法
西柚与蓝莓8 分钟前
922. 按奇偶排序数组 II 双指针 力扣
数据结构·算法·leetcode
宇柔14 分钟前
Day5:移除链表元素
数据结构·算法·链表
Amor风信子32 分钟前
【力扣】2376. 统计特殊整数
算法·leetcode·职场和发展
极客小张32 分钟前
基于正点原子Linux开发板的智能监控与家电控制系统设计:深度解析Video4Linux和TCP/IP技术栈
linux·运维·c++·物联网·网络协议·tcp/ip·算法
JustCouvrir1 小时前
代码随想录算法训练营Day5
算法
周哈里窗的编程3 小时前
CSP-CCF★201912-2回收站选址★
c++·算法·图论
SpongeG4 小时前
数据结构第三周做题总结_链表
数据结构·算法·链表
everyStudy4 小时前
前端五种排序
前端·算法·排序算法
little redcap6 小时前
第十九次CCF计算机软件能力认证-乔乔和牛牛逛超市
数据结构·c++·算法