字符串相关

128 阅读3分钟

反转字符串

问题描述:给定一个字符串,将其反转。

#include <string>  
#include <algorithm>  
  
std::string reverseString(std::string s) {  
    std::reverse(s.begin(), s.end());  
    return s;  
}  

判断字符串是否是回文

问题描述:判断一个字符串是否是回文(正着读和反着读都一样)。

#include <string>  
  
bool isPalindrome(std::string s)
{  
    int left = 0, right = s.size() - 1;  
    while (left < right)
    {  
        if (s[left++] != s[right--])
        {  
            return false;  
        }  
    }  
    return true;  
}  

最长回文子串

# 中心扩展法 时间复杂度为 O(n^2),空间复杂度为 O(1)
std::string expandAroundCenter(const std::string& s, int left, int right)
{
    int L = left, R = right;
    while (L >= 0 && R < s.length() && s[L] == s[R])
    {
        --L;
        ++R;
    }
    return s.substr(L + 1, R - L - 1);
}
 
std::string longestPalindrome(const std::string& s)
{
    if (s.empty()) return "";
    int start = 0, maxLen = 1;
    for (int i = 0; i < s.length(); ++i)
    {
        std::string odd = expandAroundCenter(s, i, i); // 奇数长度回文串
        std::string even = expandAroundCenter(s, i, i + 1); // 偶数长度回文串
        if (odd.length() > maxLen)
        {
            start = i - odd.length() / 2;
            maxLen = odd.length();
        }
        if (even.length() > maxLen)
        {
            start = i - even.length() / 2 + 1;
            maxLen = even.length();
        }
    }
    return s.substr(start, maxLen);
}

实现字符串拼接

问题描述:给定两个字符串,将它们拼接起来。

#include <string>  
  
std::string concatenateStrings(std::string s1, std::string s2) {  
    return s1 + s2;  
}  

std::string concatenateStrings(std::string s1, std::string s2) {  
    s1.append(s2);  
    return s1;  
}  

字符串中字符出现的频率

问题描述:统计字符串中每个字符出现的频率。

#include <string>  
#include <unordered_map>  
#include <iostream>  
  
std::unordered_map<char, int> charFrequency(std::string s)
{  
    std::unordered_map<char, int> freq;  
    for (char c : s)
    {  
        freq[c]++;  
    }  
    return freq;  
}  

查找字符串中的最长不重复子串长度

问题描述:给定一个字符串,找出其中最长的不包含重复字符的子串的长度。

#include <string>  
#include <unordered_set>  
#include <algorithm>  
  
int lengthOfLongestSubstring(std::string s)
{  
    std::unordered_set<char> seen;  
    int maxLength = 0, start = 0, end = 0;  
  
    while (end < s.size())
    {  
        if (seen.find(s[end]) == seen.end())
        {  
            seen.insert(s[end++]);  
            maxLength = std::max(maxLength, end - start);  
        }
        else
        {  
            seen.erase(s[start++]);  
        }  
    }  
    return maxLength;  
}  

实现字符串的全排列

#include <vector>  
#include <string>  
#include <iostream>  
#include <algorithm>  
  
void permute(std::string s, int l, int r, std::vector<std::string>& result)
{  
    if (l == r)
    {  
        result.push_back(s);  
    }
    else
    {  
        for (int i = l; i <= r; i++)
        {  
            std::swap(s[l], s[i]);  
            permute(s, l + 1, r, result);  
            std::swap(s[l], s[i]); // backtrack  
        }  
    }  
}  
  
std::vector<std::string> permuteString(std::string s) {  
    std::vector<std::string> result;  
    permute(s, 0, s.size() - 1, result);  
    return result;  
}  

---------------------------------------------------------------------------------
// 回溯算法核心函数
void backtrack(string& nums, string& track, vector<string>& res, vector<bool>& used)
{
    // base case,到达叶子节点
    if (track.size() == nums.size())
    {
        // 收集叶子节点上的值
        res.push_back(track);
        return;
    }
    // 回溯算法标准框架
    for (int i = 0; i < nums.size(); i++)
    {
        // 已经存在 track 中的元素,不能重复选择
        if (used[i])
        {
            continue;
        }
        // 做选择
        used[i] = true;
        track += nums[i];
        // 进入下一层回溯树
        backtrack(nums, track, res, used);
        // 取消选择
        track.pop_back();
        used[i] = false;
    }
}


// 主函数,输入一个不重复的字符串,返回它的全排列
vector<string> permute(string& nums)
{
    vector<string> res;
    vector<bool> used(nums.size(), false);
    string track; // 定义 track 变量
    backtrack(nums, track, res, used);
    return res;
}

// 测试代码(可选)
int main() {
    string nums = "abcd";
    vector<string> result = permute(nums);
    for (const string& perm : result)
    {
        cout << perm << endl; // 输出全排列
    }
    return 0;
}

字符串子集

//递归
// 回溯算法核心函数
void subSet(string& nums, string& track, vector<string>& res, int start)
{
    // base case,子集
    res.push_back(track);
    // 回溯算法标准框架
    for (int i = start; i < nums.size(); i++)
    {
        // 做选择
        track += nums[i];
        // 进入下一层回溯树
        subSet(nums, track, res, i + 1);
        // 取消选择
        track.pop_back();
    }
}

// 主函数,输入一个不重复的字符串,返回它的子集
vector<string> subSetStr(string& nums)
{
    vector<string> res;
    string track; // 定义 track 变量
    subSet(nums, track, res, 0);
    return res;
}

// 测试代码(可选)
int main() {
    string nums = "abc";
    vector<string> result = subSetStr(nums);
    for (const string& perm : result)
    {
        cout << perm << endl; // 输出子集
    }
    return 0;
}





//非递归实现可以通过位运算来完成
#include <iostream>
#include <string>
#include <vector>

void generateSubsets(const std::string &str)
{
    int n = str.size();
    int subsetCount = 1 << n; // 2^n 个子集

    for (int i = 0; i < subsetCount; ++i)
    {
        std::string subset;
        for (int j = 0; j < n; ++j)
        {
            if (i & (1 << j))
            { // 检查第 j 位是否为 1
                subset += str[j];
            }
        }
        std::cout << subset << std::endl;
    }
}

int main()
{
    std::string str = "ABC";
    generateSubsets(str);
    return 0;
}

字符串替换空格

问题描述:请实现一个函数,将一个字符串中的空格替换成“%20”。

#include <string>  
  
std::string replaceSpace(std::string s) {  
    std::string result;  
    for (char c : s) {  
        if (c == ' ') {  
            result += "%20";  
        } else {  
            result += c;  
        }  
    }  
    return result;  
}  

最长公共前缀

问题描述:编写一个函数来查找字符串数组中的最长公共前缀。

#include <vector>  
#include <string>  
  
std::string longestCommonPrefix(std::vector<std::string>& strs) {  
    if (strs.empty()) return "";  
  
    std::string prefix = strs[0];  
    for (size_t i = 1; i < strs.size(); ++i) {  
        size_t j = 0;  
        for (; j < prefix.size() && j < strs[i].size(); ++j) {  
            if (prefix[j] != strs[i][j]) {  
                break;  
            }  
        }  
        prefix = prefix.substr(0, j);  
        if (prefix.empty()) {  
            return "";  
        }  
    }  
    return prefix;  
}  

最长公共子序列(Longest Common Subsequence, LCS)

//时间复杂度是O(mn),空间复杂度也是O(mn),其中m和n分别是两个字符串的长度
std::string longestCommonSubsequence(const std::string& text1, const std::string& text2)
{
    int m = text1.size();
    int n = text2.size();
    
    // 创建一个二维DP数组,用于存储子问题的解
    std::vector<std::vector<int>> dp(m + 1, std::vector<int>(n + 1, 0));
    
    // 填充DP数组
    for (int i = 1; i <= m; ++i)
    {
        for (int j = 1; j <= n; ++j)
        {
            if (text1[i - 1] == text2[j - 1])
            {
                dp[i][j] = dp[i - 1][j - 1] + 1;
            }
            else
            {
                dp[i][j] = std::max(dp[i - 1][j], dp[i][j - 1]);
            }
        }
    }
    
    // 通过DP数组重建LCS
    std::string lcs;
    int i = m, j = n;
    while (i > 0 && j > 0)
    {
        if (text1[i - 1] == text2[j - 1])
        {
            lcs.push_back(text1[i - 1]);
            --i;
            --j;
        }
        else if (dp[i - 1][j] > dp[i][j - 1])
        {
            --i;
        }
        else
        {
            --j;
        }
    }
    
    // 由于我们是从后往前构建LCS的,所以需要反转字符串
    std::reverse(lcs.begin(), lcs.end());
    
    return lcs;
}

实现字符串的整数反转

问题描述:给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转。

注意:假设我们的环境只能存储得下 32 位的有符号整数,则其数值范围为 [-2^31, 2^31-1]。请根据这个假设,如果反转后整数溢出那么就返回 0。

#include <climits>  
  
int reverseInteger(int x) {  
    long long reversed = 0;  
    while (x != 0) {  
        int digit = x % 10;  
        x /= 10;  
        if (reversed > INT_MAX / 10 || (reversed == INT_MAX / 10 && digit > 7)) {  
            return 0;  
        }  
        if (reversed < INT_MIN / 10 || (reversed == INT_MIN / 10 && digit < -8)) {  
            return 0;  
        }  
        reversed = reversed * 10 + digit;  
    }  
    return static_cast<int>(reversed);  
}  

字符串的全排列 II

问题描述:给定一个可能包含重复数字的整数数组 nums,返回该数组所有可能的排列。你可以按任意顺序返回答案。

这个问题与字符串的全排列类似,只是处理的是数字数组,可以很容易地转换为字符串场景。

注意:与全排列问题相比,这个问题中的数组可能包含重复的数字,因此在生成排列时需要避免生成重复的排列。

由于这个问题的实现相对复杂,并且与字符串的全排列问题类似,因此在这里不再给出详细的代码实现。基本思路是使用回溯算法,但在添加下一个数字到当前排列中时,需要检查这个数字是否已经在当前位置被使用过,以避免生成重复的排列。

#include <vector>  
#include <algorithm>  
  
using namespace std;  
  
void backtrack(vector<vector<int>>& result, vector<int>& nums, vector<bool>& used, vector<int>& permutation) {  
    if (permutation.size() == nums.size())
    {  
        result.push_back(permutation);  
        return;  
    }  
      
    for (int i = 0; i < nums.size(); ++i)
        {  
        // 如果当前数字已经被使用过,或者当前数字与前一个数字相同且前一个数字未被使用过(为了避免重复排列)  
        if (used[i] || (i > 0 && nums[i] == nums[i - 1] && !used[i - 1])) {  
            continue;  
        }  
          
        // 做选择  
        used[i] = true;  
        permutation.push_back(nums[i]);  
          
        // 进入下一层决策树  
        backtrack(result, nums, used, permutation);  
          
        // 撤销选择  
        permutation.pop_back();  
        used[i] = false;  
    }  
}  
  
vector<vector<int>> permuteUnique(vector<int>& nums)
{  
    vector<vector<int>> result;  
    if (nums.empty()) {  
        return result;  
    }  
      
    // 首先对数组进行排序,以便在回溯过程中处理重复数字  
    sort(nums.begin(), nums.end());  
      
    // 使用一个布尔数组来标记数字是否被使用过  
    vector<bool> used(nums.size(), false);  
      
    // 辅助数组,用于构建当前排列  
    vector<int> permutation;  
      
    // 开始回溯  
    backtrack(result, nums, used, permutation);  
      
    return result;  
}