344. 反转字符串
编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 s 的形式给出。
不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1)
的额外空间解决这一问题。
示例 1:
输入:s = ["h","e","l","l","o"]
输出:["o","l","l","e","h"]
示例 2:
输入:s = ["H","a","n","n","a","h"]
输出:["h","a","n","n","a","H"]
提示:
- 1 <=
s.length
<= 105 s[i]
都是ASCII
码表中的可打印字符
C++代码:
//方法一:
class Solution {
public:
void reverseString(vector<char>& s) {
int i = 0, j = s.size() - 1;
while (i < j) {
swap(s[i++], s[j--]);
}
}
};
//方法二
class Solution {
public:
void reverseString(vector<char>& s) {
reverse(s.begin(),s.end());
}
};
541. 反转字符串 II
给定一个字符串 s
和一个整数 k
,从字符串开头算起,每计数至 2k
个字符,就反转这 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
C++代码:
class Solution {
public:
string reverseStr(string s, int k) {
for (int i = 0; i < s.size(); i += 2*k) {
if (i + k > s.size()) reverse(s.begin() + i, s.end());
else reverse(s.begin() + i, s.begin() + i + k);
}
return s;
}
};
剑指 Offer 05. 替换空格
请实现一个函数,把字符串 s
中的每个空格替换成"%20
"。
示例 1:
输入:s = "We are happy."
输出:"We%20are%20happy."
限制:
0 <= s 的长度 <= 10000
C++代码:
public:
string replaceSpace(string s) {
string res;
for (int i = 0; i < s.size(); i++) {
if (s[i] != ' ') res += s[i];
else res += "%20";
}
return res;
}
};
151.翻转字符串里的单词
给定一个字符串s
,逐个翻转字符串中的每个单词。
示例 1:
输入: "the sky is blue"
输出: "blue is sky the"
示例 2:
输入: " hello world! "
输出: "world! hello"
解释: 输入字符串可以在前面或者后面包含多余的空格,但是反转后的字符不能包括。
示例 3:
输入: "a good example"
输出: "example good a"
解释: 如果两个单词间有多余的空格,将反转后单词间的空格减少到只含一个。
解题思路:可以运用双指针先把每个单词进行反转,最后再将整个字符串进行反转。同时要消除多余的空格。
C++代码:
class Solution {
public:
string reverseWords(string s) {
int k = 0; //用k来记录反转后到串的下标用到了什么位置
for (int i = 0, j = 0; i < s.size();) {
while (j < s.size() && s[j] == ' ') j++;
if (j == s.size()) break;
i = j;
while (j < s.size() && s[j] != ' ') j++;
reverse(s.begin() + i, s.begin() + j);
if (k) s[k++] = ' ';
while (i < j) s[k++] = s[i++];
}
s.erase(s.begin() + k, s.end());
reverse(s.begin(), s.end());
return s;
}
};
// 方法二
class Solution {
public:
string reverseWords(string s) {
string res;
for (int i = 0, j = 0; i < s.size();) {
if (s[i] == ' ') {
i++;
continue;
}
j = i;
while (i < s.size() && s[i] != ' ') i++;
reverse(s.begin() + j, s.begin() + i);
res.append(s.begin() + j, s.begin() + i);
res.push_back(' ');
}
res.pop_back();
reverse(res.begin(), res.end());
return res;
}
};
剑指 Offer 58 - II. 左旋转字符串
字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。请定义一个函数实现字符串左旋转操作的功能。比如,输入字符串"abcdefg
"和数字2
,该函数将返回左旋转两位得到的结果"cdefgab
"。
示例 1:
输入: s = "abcdefg", k = 2
输出: "cdefgab"
示例 2:
输入: s = "lrloseumgh", k = 6
输出: "umghlrlose"
限制:
1 <= k < s.length <= 10000
解题思路:通过定义发现规律
C++代码:
class Solution {
public:
string reverseLeftWords(string s, int n) {
reverse(s.begin(), s.end());
reverse(s.begin(), s.end() - n);
reverse(s.end() - n, s.end());
return s;
}
};
// 方法二
class Solution {
public:
string reverseLeftWords(string s, int n) {
string res;
res.append(s.begin() + n, s.end());
res.append(s.begin(), s.begin() + n);
return res;
}
};
28. 找出字符串中第一个匹配项的下标
给你两个字符串 haystack
和 needle
,请你在 haystack
字符串中找出 needle
字符串的第一个匹配项的下标(下标从 0
开始)。如果 needle
不是 haystack
的一部分,则返回 -1
。
示例 1:
输入:haystack = "sadbutsad", needle = "sad"
输出:0
解释:"sad" 在下标 0 和 6 处匹配。
第一个匹配项的下标是 0 ,所以返回 0 。
示例 2:
输入:haystack = "leetcode", needle = "leeto"
输出:-1
解释:"leeto" 没有在 "leetcode" 中出现,所以返回 -1 。
提示:
- 1 <=
haystack.length, needle.length
<= 104 haystack
和needle
仅由小写英文字符组成
解题思路:
这道题题意是要求从字符串中找到一个子串与模式串相匹配,并返回第一个匹配项的下标。从长字符串中寻找特定模式串的问题可使用kmp
算法。首先求得模式串的next
数组,然后在将模式串和长字符串进行匹配。
C++代码:
class Solution {
public:
int strStr(string s, string p) {
if (p.empty()) return 0;
int n = s.size(), m = p.size();
s = ' ' + s; //kmp算法中字符串下标通常从1开始
p = ' ' + p;
vector <int> ne(m + 1);
for (int i = 2, j = 0; i <= m; i++) {
while (j && p[i] != p[j + 1]) j = ne[j]; //当以i结尾的字符串p的第i个位置和p串前缀的j+1的位置值不相等
//此时失配,需要移动j的位置重新进行匹配
if (p[i] == p[j + 1]) j++;
ne[i] = j;
}
for (int i = 1, j = 0; i <= n; i++) {
while (j && s[i] != p[j + 1]) j = ne[j];
if (s[i] == p[j + 1]) j++;
if (j == m)
return i - m; //这里的取值和字符串下标相关,注意下标的取值
}
return -1;
}
};
459. 重复的子字符串
给定一个非空的字符串 s
,检查是否可以通过由它的一个子串重复多次构成。
示例 1:
输入: s = "abab"
输出: true
解释: 可由子串 "ab" 重复两次构成。
示例 2:
输入: s = "aba"
输出: false
示例 3:
输入: s = "abcabcabcabc"
输出: true
解释: 可由子串 "abc" 重复四次构成。 (或子串 "abcabc" 重复两次构成。)
提示:
1 <= s.length
<= 104
s
由小写英文字母组成
解题思路:
这道题题意是检查字符串是否由一个子串重复多次构成,那么也就是说我们需要寻找到一个周期,并判断这个周期的子串能不能构成原字符串。这里我首先提出两条性质:
- 如果非空字符串
s
的长度为n
,字符串s
的最长公共前后缀长度为next[n]
,则t = n - next[n]
为字符串s
的最小周期,此时字符串s
的最后一个周期的子串并不一定完整。 - 如果最小周期
t
可以整除n
,则最小周期t
一定是其他所有周期的约数。
C++代码:
class Solution {
public:
bool repeatedSubstringPattern(string s) {
int n = s.size();
s = ' ' + s;
vector<int> next(n + 1);
for (int i = 2, j = 0; i <= n; i++) {
while (j && s[i] != s[j + 1]) j = next[j];
if (s[i] == s[j + 1]) j ++;
next[i] = j;
}
int t = n - next[n]; //t是字符串s的最小周期,并且字符串s中的最后一个周期t可以不完整。
return t < n && n % t == 0; //如果最小周期可以整除n,则最小周期一定是其他所有周期的约数。
}
};