第344题 反转字符串
![](https://i-blog.csdnimg.cn/blog_migrate/02fb8a9aad8d21e9b63c0384e8eb1ad2.png)
解题思路:双指针法,定义两个指针,一个位于首端,一个在尾端,互相交换元素即可,注意循环终止条件。
class Solution {
public:
void reverseString(vector<char>& s) {
//求字符串的长度
int len = s.size();
//双指针,一个指首端,一个指尾端
int left = 0,right = len-1;
while(left<right)
{
//开始反转
int temp = s[left];
s[left] = s[right];
s[right] = temp;
//移动首尾指针
left++;
right--;
}
}
};
第541题 反转字符串
![](https://i-blog.csdnimg.cn/blog_migrate/06c61d91fd0228ab10b1f599d2604f27.png)
解题思路:题目整体不难,主要都是细节问题,主要思想是将整个字符串以2*k大小进行分组,然后在每个分组内反转前k个,主要分为以下三种情况:
字符串长度小于k,则将整个链表进行反转
字符串长度大于k,则开始第一组【0~2*k】内前k个进行反转
当执行到最后一个分组的时候,判断当前剩余长度是否大于k若是,继续进行前k个反转,否则,将剩余部分全部反转。
class Solution {
public:
void reverseString(string& s,int begin,int end) {
//双指针,一个指首端,一个指尾端
int left = begin,right = end-1;
while(left<right)
{
//开始反转
int temp = s[left];
s[left] = s[right];
s[right] = temp;
//移动首尾指针
left++;
right--;
}
}
string reverseStr(string s, int k) {
int len = s.size();
//当字符串长度小于k,全部反转
if (len < k)
{
reverseString(s, 0, len);
return s;
}
else
{
int i = 0;
while (i < len)
{
int r_len = len - i;//右边剩余长度
//当剩余字符不足2*k个,即最后一个分组
//也分两种情况,第一种情况是剩余长度小于k,第二种情况是剩余长度大于k但是小于2*k;
if (r_len < k)
{
reverseString(s, i, len);
return s;
}
else
reverseString(s, i, i + k);
i += k * 2;
}
return s;
}
}
};
剑指offer 05 替换空格
![](https://i-blog.csdnimg.cn/blog_migrate/ef68e25af3daa9571b8083a895ef129c.png)
解题思路:首先要明确"%20"不能一下子直接替换空格,因此原字符串需要扩容。采用双指针思想,从后往前开始遍历。为什么要从后向前填充,从前向后填充不行么?从前向后填充就是O(n^2)的算法了,因为每次添加元素都要将添加元素之后的所有元素向后移动。很多数组填充类的问题,都可以先预先给数组扩容带填充后的大小,然后在从后向前进行操作。这么做有两个好处:
不用申请新数组。
从后向前填充元素,避免了从前向后填充元素时,每次添加元素都要将添加元素之后的所有元素向后移动的问题。
class Solution {
public:
string replaceSpace(string s) {
int len = s.size();
//统计空格个数
int count = 0;
for (int i = 0; i < len; i++)
if (s[i] == ' ')
count++;
//给s扩充空间,原来的''可以被%取代,但是字符2和0还需要重新给分配空间
s.resize(len + count * 2);
int newlen = s.size();
//从后向前遍历,并且使用双指针,一个指原字符串尾,一个指新字符串尾(事实上物理空间是同一块)
for (int i = newlen - 1, j = len - 1; j < i; i--, j--)
{
//没遍历到空格时,一个一个向后挪
if (s[j] != ' ')
s[i] = s[j];
else
{
s[i] = '0';
s[i - 1] = '2';
s[i - 2] = '%';
i -= 2;//填充完要向前挪两步
}
}
return s;
}
};
第151题 反转字符串中的单词
![](https://i-blog.csdnimg.cn/blog_migrate/eebfe977104a1984ce545feb82730557.png)
解题思路:先移除多余空格,再将整个字符串反转,最后将每个单词反转。
class Solution {
public:
void reverse(string& s, int start, int end)
{ //翻转,区间写法:左闭右闭 []
for (int i = start, j = end; i < j; i++, j--)
swap(s[i], s[j]);
}
string reverseWords(string s) {
//三步走:先删除字符串中多余的空格;再直接交换字符(交换完单词是反的);对单词进行反转
//第一步:移除多余空格(双指针法)
int slow = 0;
for (int first = 0; first < s.size(); ++first)
{
if (s[first] != ' ')
{ //遇到非空格就处理,即删除所有空格。
if (slow != 0) s[slow++] = ' '; //手动控制空格,给单词之间添加空格。slow != 0说明不是第一个单词,需要在单词前添加空格。
while (first < s.size() && s[first] != ' ') { //补上该单词,遇到空格说明单词结束。
s[slow++] = s[first++];
}
}
}
s.resize(slow); //slow的大小即为去除多余空格后的大小。
int len = s.size();
//第二步:将整个字符串逆转
reverse(s, 0, len - 1);
//第三步:将逆序的单词正过来
int start = 0;
for (int i = 0; i <= len; i++)
{
if (i == len || s[i] == ' ')//到达一个单词的尾部,则开始反转
{
reverse(s, start, i - 1);
//重新移动start
start = i + 1;
}
}
return s;
}
};
剑指offer58-Ⅱ 左旋转字符串
![](https://i-blog.csdnimg.cn/blog_migrate/ad94bbfc4ce0bdf151c1b66e2a24ae7c.png)
解题思路:更上面的题类似,先部分反转,再整体反转。
class Solution {
public:
string reverseLeftWords(string s, int n) {
//该函数传的是地址
//前k个反转
reverse(s.begin(), s.begin() + n);
//后n-k个反转
reverse(s.begin() + n, s.end());
//整体反转
reverse(s.begin(), s.end());
return s;
}
};
第28题 找出字符串中第一个匹配项的下标
![](https://i-blog.csdnimg.cn/blog_migrate/c9fcb32233ef14067a3daf02429d390e.png)
解题思路:滑动窗口,每次在haystack 上截取needle 长度的子串,比较是否相等,若找到相等的,直接返回下标,若遍历结束,返回-1。
class Solution {
public:
bool isequal(string haystack, int start, int end, string needle)
{
for (int i=start,j=0;i<end;i++,j++)
{
if (haystack[i] != needle[j])
return false;
}
return true;
}
int strStr(string haystack, string needle) {
//滑动窗口,窗口大小为needle.size()
int len = needle.size();
for (int i = 0,j = i+len;j<=haystack.size(); i++,j++)
{
//判断当前窗口和needle是否相等
if (isequal(haystack, i, j, needle))
return i;
}
return -1;
}
};
还有一个KMP算法专用来,之后单独写一篇文章来学习一下。