【算法题】字符串

字符串是算法面试的高频核心考点,核心考察字符遍历、边界处理、进制运算模拟、回文特性利用等能力。本文通过4道经典字符串题目,拆解不同场景下的解题技巧,涵盖公共前缀查找、回文子串求解、二进制加法、大数乘法等核心场景。

一、最长公共前缀

题目描述:

编写一个函数查找字符串数组中的最长公共前缀,若不存在公共前缀则返回空字符串 ""

示例

  • 输入:strs = ["flower","flow","flight"],输出:"fl"
  • 输入:strs = ["dog","racecar","car"],输出:""

解题思路:

以第一个字符串为基准,逐字符对比所有字符串的对应位置

  1. 遍历第一个字符串的每个字符(索引 i),取该字符作为基准字符 tmp
  2. 遍历数组中其他所有字符串:
    • 若某字符串的索引 i 超出自身长度(如 "flow""flower" 短),说明公共前缀截止到 i-1
    • 若某字符串索引 i 的字符与 tmp 不同,同样截止到 i-1
  3. 若所有字符都匹配,直接返回第一个字符串。

完整代码:

cpp 复制代码
class Solution {
public:
    string longestCommonPrefix(vector<string>& strs) {
        for(int i = 0; i < strs[0].size(); i++)
        {
            char tmp = strs[0][i];
            for(int j = 1; j < strs.size(); j++)
                if(i == strs[j].size() || strs[j][i] != tmp) 
                    return strs[0].substr(0, i);
        }
        return strs[0];
    }
};

复杂度分析:

  • 时间复杂度:O(nm)O(nm)O(nm),n 是字符串数组长度,m 是最长公共前缀的长度(最坏情况遍历所有字符串的所有字符)。
  • 空间复杂度:O(1)O(1)O(1),仅用常数级额外变量。

二、最长回文子串

题目描述:

给定字符串 s,找到其中最长的回文子串(回文:正读和反读相同的字符串)。

示例

  • 输入:s = "babad",输出:"bab"(或 "aba"
  • 输入:s = "cbbd",输出:"bb"

解题思路:

中心扩展法(回文的核心特性:以单个字符为中心(奇数长度)或两个相同字符为中心(偶数长度)向两侧扩展):

  1. 遍历字符串的每个字符,分别处理两种情况:
    • i 为中心(奇数长度回文):left = iright = i
    • ii+1 为中心(偶数长度回文):left = iright = i+1
  2. 向两侧扩展,直到左右字符不相等,记录当前回文子串的长度和起始位置。
  3. 遍历结束后,返回最长的回文子串。

完整代码:

cpp 复制代码
class Solution {
public:
    string longestPalindrome(string s) {
        int len = 0, begin = 0;
        for(int i = 0; i < s.size(); i++)
        {
            // 奇数长度回文
            int left = i, right = i;
            while(left >= 0 && right <= s.size() && 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 <= s.size() && s[left] == s[right])
            {
                left--;
                right++;
            }
            if(right - left - 1 > len)
            {
                len = right - left - 1;
                begin = left + 1;
            }
        }
        return s.substr(begin, len);
    }
};

复杂度分析:

  • 时间复杂度:O(n2)O(n^2)O(n2),n 是字符串长度,每个字符最多向两侧扩展 O(n)O(n)O(n) 次。
  • 空间复杂度:O(1)O(1)O(1),仅用常数级额外变量。

三、二进制求和

题目描述:

给定两个二进制字符串 ab,返回它们的和(以二进制字符串形式)。

示例

  • 输入:a = "11", b = "1",输出:"100"
  • 输入:a = "1010", b = "1011",输出:"10101"

解题思路:

模拟手工二进制加法过程(从后往前遍历,处理进位):

  1. t 存储进位,cur1/cur2 分别指向两个字符串的末尾(最低位)。
  2. 遍历过程中累加当前位的值和进位:
    • cur1/cur2 未越界,将对应字符转为数字累加到 t
    • 当前位结果为 t % 2(二进制取余),新的进位为 t / 2
  3. 遍历结束后反转结果字符串(因拼接时是从低位到高位)。

完整代码:

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

复杂度分析:

  • 时间复杂度:O(max⁡(n,m))O(\max(n,m))O(max(n,m)),n/m 是两个字符串的长度,遍历次数为较长字符串的长度。
  • 空间复杂度:O(1)O(1)O(1)(结果字符串为必要输出,不计入额外复杂度)。

四、字符串相乘

题目描述:

给定两个以字符串形式表示的非负整数 num1num2,返回它们的乘积(同样以字符串形式表示)。

示例

  • 输入:num1 = "2", num2 = "3",输出:"6"
  • 输入:num1 = "123", num2 = "456",输出:"56088"

解题思路:

模拟大数乘法的手工计算过程(反转字符串简化低位计算,数组存储中间乘积):

  1. 反转两个字符串,方便从低位(原字符串末尾)开始计算。
  2. 用数组 tmp 存储每一位的乘积结果:num1[i] * num2[j] 的结果对应 tmp[i+j](手工乘法中,个位乘个位对应结果的个位,个位乘十位对应结果的十位)。
  3. 处理数组的进位,拼接结果字符串,反转后返回(注意去除末尾多余的0)。

完整代码:

cpp 复制代码
class Solution {
public:
    string multiply(string num1, string num2) {
        int n = num1.size(), m = num2.size();
        reverse(num1.begin(), num1.end());
        reverse(num2.begin(), num2.end());
        vector<int> tmp(m + n - 1);

        // 计算每一位的乘积
        for(int i = 0; i < num1.size(); i++)
            for(int j = 0; j < num2.size(); j++)
                tmp[i + j] += (num1[i] - '0') * (num2[j] - '0');

        // 处理进位
        int t = 0, cur = 0;
        string ret;
        while(cur < m + n - 1 || t)
        {
            if(cur < m + n - 1) t += tmp[cur++];
            ret += (t % 10) + '0';
            t /= 10;
        }

        // 去除末尾的0(避免结果为"0000"的情况)
        while(ret.back() == '0' && ret.size() > 1) ret.pop_back();
        reverse(ret.begin(), ret.end());
        return ret;
    }
};

复杂度分析:

  • 时间复杂度:O(nm)O(nm)O(nm),n/m 是两个字符串的长度,双层循环计算乘积。
  • 空间复杂度:O(n+m)O(n+m)O(n+m),数组 tmp 的长度为 n+m-1,用于存储中间乘积结果。
相关推荐
仰泳的熊猫3 小时前
题目2570:蓝桥杯2020年第十一届省赛真题-成绩分析
数据结构·c++·算法·蓝桥杯
无极低码7 小时前
ecGlypher新手安装分步指南(标准化流程)
人工智能·算法·自然语言处理·大模型·rag
软件算法开发7 小时前
基于海象优化算法的LSTM网络模型(WOA-LSTM)的一维时间序列预测matlab仿真
算法·matlab·lstm·一维时间序列预测·woa-lstm·海象优化
罗超驿7 小时前
独立实现双向链表_LinkedList
java·数据结构·链表·linkedlist
superior tigre8 小时前
22 括号生成
算法·深度优先
努力也学不会java9 小时前
【缓存算法】一篇文章带你彻底搞懂面试高频题LRU/LFU
java·数据结构·人工智能·算法·缓存·面试
旖-旎9 小时前
二分查找(x的平方根)(4)
c++·算法·二分查找·力扣·双指针
ECT-OS-JiuHuaShan9 小时前
朱梁万有递归元定理,重构《易经》
算法·重构
智者知已应修善业10 小时前
【51单片机独立按键控制数码管移动反向,2片74CH573/74CH273段和位,按键按下保持原状态】2023-3-25
经验分享·笔记·单片机·嵌入式硬件·算法·51单片机