反转字符串
问题描述:给定一个字符串,将其反转。
#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;
}