字符串算法专题


节选了字符串部分的一些有共性和特性的一些题目

5.最长回文字符串

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


示例1:

输入:s = “babad”
输出:”bab”
解释:”aba” 同样是符合题意的答案。
示例 2:

输入:s = “cbbd”
输出:”bb”
示例 3:

输入:s = “a”
输出:”a”
示例 4:

输入:s = “ac”
输出:”a”



提示:

1 <= s.length <= 1000
s 仅由数字和英文字母(大写和/或小写)组成


法一:中心扩散法

class Solution {
public:
    vector maxlength(string s, int start, int end){
        int n  = s.size() ;
        vector ans(2) ;
        while(start>= 0 && end ji(2) ; vector ou(2)  ; vector result(2) ; 
        int n = s.size() ;
        if(n == 1) return s ;
        int max =0  ; 
        for(int i = 0 ;iou[1] ? ji[1]:ou[1] ;
            if(length>max){
                max = length ;
                result = ji[1]>ou[1] ? ji:ou ;
            }
        } 
        return s.substr (result[0], result[1]) ;
    }
};

法二:动态规划法

class Solution {
public:
    string longestPalindrome(string s) {
        int n = s.size();
        if (n < 2) {
            return s;
        }

        int maxLen = 1;
        int begin = 0;
        // dp[i][j] 表示 s[i..j] 是否是回文串
        vector>  dp(n, vector(n));
        // 初始化:所有长度为 1 的子串都是回文串
        for (int i = 0; i < n; i++) {
            dp[i][i] = true;
        }
        // 递推开始
        // 先枚举子串长度
        for (int L = 2; L <= n; L++) {
            // 枚举左边界,左边界的上限设置可以宽松一些
            for (int i = 0; i < n; i++) {
                // 由 L 和 i 可以确定右边界,即 j - i + 1 = L 得
                int j = L + i - 1;
                // 如果右边界越界,就可以退出当前循环
                if (j >= n) {
                    break;
                }

                if (s[i] != s[j]) {
                    dp[i][j] = false;
                } else {
                    if (j - i < 3) {
                        dp[i][j] = true;
                    } else {
                        dp[i][j] = dp[i + 1][j - 1];
                    }
                }

                // 只要 dp[i][L] == true 成立,就表示子串 s[i..L] 是回文,此时记录回文长度和起始位置
                if (dp[i][j] && j - i + 1 > maxLen) {
                    maxLen = j - i + 1;
                    begin = i;
                }
            }
        }
        return s.substr(begin, maxLen);
    }
};

516.最长回文子序列


给你一个字符串 s ,找出其中最长的回文子序列,并返回该序列的长度。

子序列定义为:不改变剩余字符顺序的情况下,删除某些字符或者不删除任何字符形成的一个序列。



示例 1:

输入:s = “bbbab”
输出:4
解释:一个可能的最长回文子序列为 “bbbb” 。
示例 2:

输入:s = “cbbd”
输出:2
解释:一个可能的最长回文子序列为 “bb” 。



提示:

  • 1 <= s.length <= 1000
  • s 仅由小写英文字母组成

法一:动态规划法

class Solution {
public:
    int longestPalindromeSubseq(string s) {
        int n = s.size() ;
        vector> dp(n,vector(n,0)); //初始化二维的容器
        for(int i = 0;i=0;i--){
                if(s[i] == s[j])
                dp[i][j] = dp[i+1][j-1] +2 ;
                else
                dp[i][j] = max(dp[i+1][j],dp[i][j-1]) ;
            }
        }
       return dp[0][n-1] ;
    }
};

541.反转字符串II


给定一个字符串 s 和一个整数 k,从字符串开头算起,每 2k 个字符反转前 k 个字符。

如果剩余字符少于 k 个,则将剩余字符全部反转。
如果剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符,其余字符保持原样。



示例 1:

输入:s = “abcdefg”, k = 2
输出:”bacdfeg”
示例 2:

输入:s = “abcd”, k = 2
输出:”bacd”


提示:

1 <= s.length <= 104
s 仅由小写英文组成
1 <= k <= 104


class Solution {
public:
    string reverseStr(string s, int k) {
        int n = s.size() ;
        for(int i = 0;i

763.划分字母区间


字符串 S 由小写字母组成。我们要把这个字符串划分为尽可能多的片段,同一字母最多出现在一个片段中。返回一个表示每个字符串片段的长度的列表。



示例:

输入:S = “ababcbacadefegdehijhklij”
输出:[9,7,8]
解释:
划分结果为 “ababcbaca”, “defegde”, “hijhklij”。
每个字母最多出现在一个片段中。
像 “ababcbacadefegde”, “hijhklij” 的划分是错误的,因为划分的片段数较少。



提示:

  • S的长度在[1, 500]之间。
  • S只包含小写字母 'a''z'

class Solution {
public:
    vector partitionLabels(string s) {
       vectorans,ends(26,-1) ;          //这一步是申请两个vector,一个是用来return,一个是用来反映元素最后出现的位置信号
       for(int i = 0;i

680.验证回文字符串II


给定一个非空字符串 s最多删除一个字符。判断是否能成为回文字符串。



示例 1:

输入: s = “aba”
输出: true
示例 2:

输入: s = “abca”
输出: true
解释: 你可以删除c字符。
示例 3:

输入: s = “abc”
输出: false



提示:

  • 1 <= s.length <= 105
  • s 由小写英文字母组成

class Solution {
public:
    bool validPalindrome(string s) {
    if(s.length() <= 2)
    return true ;
    else{
      int left = 0 ;
      int right = s.length()-1 ;
      while(left

49.字母异位词分组


给你一个字符串数组,请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。

字母异位词 是由重新排列源单词的字母得到的一个新单词,所有源单词中的字母都恰好只用一次。



示例 1:

输入: strs = [“eat”, “tea”, “tan”, “ate”, “nat”, “bat”]
输出: [[“bat”],[“nat”,”tan”],[“ate”,”eat”,”tea”]]
示例 2:

输入: strs = [“”]
输出: [[“”]]
示例 3:

输入: strs = [“a”]
输出: [[“a”]]



提示:

  • 1 <= strs.length <= 104
  • 0 <= strs[i].length <= 100
  • strs[i] 仅包含小写字母

class Solution {
public:
    vector> groupAnagrams(vector& strs) {
        int num[26] = {2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101} ;
        unordered_map> mp ;
        vector> result ;
        for(string s : strs){
            unsigned long long key = 1 ;
            for(char c: s){
                key *= num[c-'a'] ;
            }
            mp[key].push_back(s) ;
        }
        for(auto p : mp){
            result.push_back(p.second) ;
        }
        return result ;
    }
};

524.通过删除字母匹配到字典里最长单词


给你一个字符串 s 和一个字符串数组 dictionary 作为字典,找出并返回字典中最长的字符串,该字符串可以通过删除 s 中的某些字符得到。

如果答案不止一个,返回长度最长且字典序最小的字符串。如果答案不存在,则返回空字符串。



示例 1:

输入:s = “abpcplea”, dictionary = [“ale”,”apple”,”monkey”,”plea”]
输出:”apple”
示例 2:

输入:s = “abpcplea”, dictionary = [“a”,”b”,”c”]
输出:”a”



提示:

1 <= s.length <= 1000
1 <= dictionary.length <= 1000
1 <= dictionary[i].length <= 1000
s 和 dictionary[i] 仅由小写英文字母组成


class Solution {
public:
    string findLongestWord(string s, vector& dictionary) {
     sort(dictionary.begin(),dictionary.end(),[](string a,string b){
         if(a.length() == b.length())
         return ab.length() ;
     }) ;
     for(string str:dictionary){
        int i = 0 ;
        for(char c: s){
            if(i

76.最小覆盖子串

443.压缩字符串


文章作者: 罗林
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 罗林 !
  目录