【ONE·基础算法 || 字符串】

在这里插入图片描述

总言

  主要内容:编程题举例,熟悉理解字符串类题型。
  
  


  
  
  
  

1、字符串

  主要在于熟悉字符串类的OJ题常用容器和接口。主要与其它算法结合使用。
  
  
  

2、最长公共前缀(easy)

  题源:链接

在这里插入图片描述
  
  

2.1、题解

  1)、思路分析
  这里需要注意理解,一个字符串的前缀是从该字符串的第一个字符起始的一个子串
  方法一: 字符串两两比较,可以先找出前两个的最长公共前缀,然后拿这个最长公共前缀依次与后⾯的字符串比较,获取新的最长公共前缀,这样所有字符串比较完成,就能获取到最终结果。

在这里插入图片描述
  
  方法二: 统一比较所有字符串中 i 位置处的字符是否相同。何时结束比较?(遍历到某一字符串的尾部,或当前遍历字符与其它字符不相同,说明此前的字符均为公共前缀。)
在这里插入图片描述

  
  
  2)、题解
  字符串两两进行比较的写法:

class Solution {
public:
    string longestCommonPrefix(vector<string>& strs) {
        //一个字符串的前缀是从该字符串的第一个字符起始的一个子串
        string ret = strs[0];//PS:数组中只有一个字符串,也满足条件(不进入循环,直接返回strs[0])。
        for(int i = 1; i < strs.size(); ++i)
        {
            ret = stringcompare(ret,strs[i]);
        }
        return ret;
    }

    //两字符串比较
    string stringcompare(string& s1, string& s2)
    {
        int i = 0;
        int len = min(s1.size(), s2.size());
        while(i < len && s1[i] == s2[i]) //当两字符串均存在,且当前位置元素相同时
            i++;
        return s1.substr(0,i);//string substr (size_t pos = 0, size_t len = npos) const;
    }
};

  
  字符串统一进行比较的写法:

class Solution {
public:
    string longestCommonPrefix(vector<string>& strs) {
        
        string ref = strs[0];//以第一个字符串作为参照,后续字符串进行比较判断
        for(int i = 0; i < ref.size(); ++i)//遍历字符串strs[0],与其它字符串逐个比较i位置处的字符
        {
            for(int j = 1; j < strs.size(); ++j)//j表示第j个字符串,比较的是其第i个字符。
            {
                if(i > strs[j].size() || ref[i] != strs[j][i])//这里字符长度与字符元素都要进行判断
                    return ref.substr(0,i);
            }
        }
        return ref;
    }
};

  
  
  
  
  

3、最长回文子串 (medium)

  题源:链接

在这里插入图片描述

  
  

3.1、题解

  1)、思路分析
  我们可以利用回文子串的性质。若一个字符串是回文串,从其中心位置开始向两边扩散,有左右两侧元素相等。
在这里插入图片描述
  以上是回文子串长度为奇数的情况,设当前遍历到的元素 i 为中心元素,则有left = i -1,right = i + 1,比较判断s[left]s[right],若符合则继续往两侧扩散寻找。
  此外,我们还需要考虑偶数情况。如下:可以让left = i; right = i + 1right = i; left = i - 1,依次往两边扩散比较。
  
在这里插入图片描述
  
  
  2)、题解
  整体可以套两层循环完成,外层用于遍历中心元素i,寻找每回合的回文子串,内层用于判断当前回合中,回文子串的扩散长度。

class Solution {
public:
    string longestPalindrome(string s) {
        int n = s.size();
        int begin = 0; // 用于记录最长数组的起始下标。
        int len = 0;   // 用于记录最长数组的长度。
        for (int i = 0; i < n; ++i) {

            // 以i为中点,向两边扩散
            // 以偶数扩展
            int left = i;
            int right = i + 1;
            while (left >= 0 && right <= n - 1 && s[left] == s[right]) {
                left--;
                right++;
            }

            if (right - left - 1 > len) {
                begin = left + 1;
                len = right - left - 1; // (right - 1) - (left + 1) + 1;
            }

            // 以奇数扩展
            left = i;
            right = i;
            while (left >= 0 && right <= n - 1 && s[left] == s[right]) {
                left--;
                right++;
            }

            if (right - left - 1 > len) {
                begin = left + 1;
                len = right - left - 1; // (right - 1) - (left + 1) + 1;
            }
        }
        return s.substr(begin, len);
    }
};

  
  
  
  
  
  
  

4、二进制求和(easy):高精度加法

  题源:链接

在这里插入图片描述

  
  

4.1、题解

  1)、思路分析
  背景介绍: 此题实则为 高精度计算。高精度计算通常用于处理那些超出了标准数据类型(如 int, float, double 等)能够表示的范围或精度的数字。高精度计算通常涉及字符串或数组来表示大数字,并使用特殊的算法来进行加、减、乘、除等操作。
  
  
  题解: 类似这样的题,我们在链表的两数相加中也做过,这里运用的方法原理不变,模拟列竖式计算两个数之和的过程即可。需要注意:
  ①这里是二进制,因此两数相加时应该是逢二进一
  ②链表的题里直接给了我们逆序,方便了位数之间的运算,这里题目给我们的是正常顺序的字符串,在进行运算时需要对进位做处理。
  
  

  2)、题解
  以下为题解,总思想不变。但这里我们从字符串末尾开始往前运算。对于最终输出结果,可以先获取到一个逆序的字符串再逆置回来,或者直接使用头插获得正序的字符串。

class Solution {
public:
    string addBinary(string a, string b) {
        int sum = 0;//用于记录相位运算结果
        int cur1 = a.size()-1, cur2 =b.size()-1;//分别用于遍历两字符串(注意运算要从低位开始,这里是字符串尾位置)
        string ret;//用于记录返回结果
        while(cur1 >= 0 || cur2 >= 0 || sum)
        {
            if(cur1 >= 0)
                sum += a[cur1--] -'0';
            if(cur2 >= 0)
                sum += b[cur2--] -'0';

            ret += sum % 2 + '0';
            //ret.insert(0, 1, sum % 2 + '0');//若不用+=结合逆置,这里也可以用insert头插

            sum /= 2;
        }
        reverse(ret.begin(),ret.end());//字符串逆置
        return ret;
    }
};

  
  
  
  
  
  
  
  

5、字符串相乘(medium):高精度乘法

  题源:链接

在这里插入图片描述  
  

5.1、题解

  1)、思路分析
  此题方法:无进位相乘然后相加,最后处理进位。
  整体思路就是模拟我们列竖式计算两个数相乘的过程。但是为了书写代码的方便性,可对其进行优化:在计算两数相乘的时候,先不考虑进位,等到所有结果计算完毕之后,再去考虑进位。 (所得结果和常规的列竖式计算相同)
在这里插入图片描述
  关于两数相乘的位数证明:相关链接
  
  2)、题解
  

class Solution {
public:
    string multiply(string num1, string num2) {
        //先对字符串逆序
        reverse(num1.begin(), num1.end());
        reverse(num2.begin(), num2.end());
        int m = num1.size();
        int n = num2.size();
		
        vector<int> tmp(m + n -1);//用于存储无进位相乘后相加结果
        //无进位相乘相加
        for(int i = 0; i < n; ++i)
        {
            for(int j = 0; j < m; ++j)
            {
                tmp[j+i] += (num2[i] - '0')*(num1[j] - '0');//这里要注意相乘后结果应该放在哪位上。
            }
        }
        //处理结果(tmp数组,处理进位)
        int sum = 0; int i = 0;
        string ret;
        while(i < tmp.size() || sum)
        {
            if(i <tmp.size())
                sum += tmp[i++];
            ret += sum % 10 + '0';
            sum /= 10;
        }
        //处理前导零
        while(ret.size() > 1 && ret.back() == '0') ret.pop_back();
        //逆置返回
        reverse(ret.begin(), ret.end());
        return ret;
    }
};

  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  

Fin、共勉。

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值