C++刷题笔记(11)——leetcode344、541、剑指Offer05、151、剑指Offer58

题目1:344.反转字符串

在这里插入图片描述

解法:双指针法

字符串也可以理解成一种数组,然后定义前后两个指针,同时向中间移动并交换元素
在这里插入图片描述

class Solution {
public:
    void reverseString(vector<char>& s) {
        for (int left = 0, right = s.size() - 1; left < right; left++, right--) {    //条件也可以改成left<.size()/2   遍历到字符串的一半就可以返回结果
            swap(s[left], s[right]);
        }
    }
};

题目2:541.反转字符串Ⅱ

在这里插入图片描述

解法:模拟

反转每个下标从 2k2k 的倍数开始的,长度为 kk 的子串。若该子串长度不足 kk,则反转整个子串。

class Solution {
public:
	string reverseStr(string s, int k) {
		for (int i = 0; i < s.size(); i += (2 * k)) {        //使用+=让i每次移动2k,然后判断是否反转
			if (i + k <= s.size()) {    //1.每隔2k个字符的前k个字符进行反转    2.剩余字符小于2k但大于或等于k个,则反转前k个字符
				reverse(s.begin() + i, s.begin() + i + k);   //reverse()会将区间[beg,end)内的元素全部逆序
				continue;                                    //直接进入下一轮循环
			}
			reverse(s.begin() + i, s.begin() + s.size());   //3.剩余字符少于 k 个,则将剩余字符全部反转
		}
		return s;
	}
};

官方给出的代码更加简洁:

class Solution {
public:
	string reverseStr(string s, int k) {
		int n = s.length();
		for (int i = 0; i < n; i += 2 * k) {
			reverse(s.begin() + i, s.begin() + min(i + k, n));
		}
		return s;
	}
};

题目3:剑指Offer05.替换空格

在这里插入图片描述

解法:双指针法

解题思路:
将空格变成%20(一个字符变成三个字符),因此可以将字符串的大小resize,然后遍历字符串将空格替换成%20
在这里插入图片描述
如果从前向后填充,时间复杂度就变成了O(n2),因为每次添加元素都要将添加元素之后的所有元素向后移动。

class Solution {
public:
	string replaceSpace(string s) {
		int count = 0;                           //空格数
		int oldsize = s.size();                  //替换前的字符串长度
		for (int i = 0; i < oldsize; i++) {      //统计字符串中的空格数
			if (s[i] == ' ') {
				count++;
			}
		}
		s.resize(s.size() + 2*count);                        //扩充字符串
		int newsize = s.size();                                //扩充后字符串长度
		//从后向前将空格替换为%20
		for (int i = newsize-1, j = oldsize-1; j < i; i--, j--) {     //i指向新长度的末尾,j指向旧长度的末尾
			if (s[j] != ' ') {
				s[i] = s[j];
			}
			else {
				s[i] = '0';
				s[i - 1] = '2';
				s[i - 2] = '%';
				i -= 2;
			}
		}
		return s;
	}
};

评论区大佬用了字符数组的解法,非常的巧妙:
与双指针法相比,双指针法是在原来的字符串中进行改动,字符数组是重新创建了一个新的数组

class Solution {
public:
    string replaceSpace(string s) {     //字符数组
        string array;                   //存储结果
        
        for(auto &c : s){              //遍历原字符串
            if(c == ' '){
                array.push_back('%');
                array.push_back('2');
                array.push_back('0');
            }
            else{
                array.push_back(c);
            }
        }
        return array;
    }
};

题目4:151.颠倒字符串中的单词

在这里插入图片描述

解法一

倒序遍历,超级简单的代码

class Solution {
public:
    string reverseWords(string s) {
        string result;                                             //存放结果的字符串
        int i = s.size();                 
        while (i) {                                                //倒叙遍历字符串
            int count = 0;                                         //计数有多少个非空格的字符
            while (i > 0 && s[i] == ' ') i--;                      //遍历空格
            while (i > 0 && s[i] != ' ') i--, count++;             //遍历字符
            if (count > 0) result += s.substr(i + 1, count) + ' '; //截取的是从i+1开始(此时的i已经不指向字符),截取count个字符
        }
        return result.substr(0, result.size() - 1);                //最后的result中多了个空格,要注意去掉
    }
};

解法二:双端队列+双指针

官方提供了一种双端队列的方法,即[deque容器,支持从队列头部插入的方法
C++ STL deque容器(详解版)

沿着字符串一个一个单词处理,然后将单词压入队列的头部,再将队列转成字符串即可。
在这里插入图片描述

class Solution {
public:
    string reverseWords(string s) {
        int left = 0, right = s.size() - 1;
        // 去掉字符串开头的空白字符
        while (left <= right && s[left] == ' ') ++left;

        // 去掉字符串末尾的空白字符
        while (left <= right && s[right] == ' ') --right;

        deque<string> d;
        string word;

        while (left <= right) {
            char c = s[left];
            if (word.size() && c == ' ') {
                // 将单词 push 到队列的头部
                d.push_front(move(word));
                word = "";
            }
            else if (c != ' ') {
                word += c;
            }
            ++left;
        }
        d.push_front(move(word));
        
        string ans;
        while (!d.empty()) {
            ans += d.front();
            d.pop_front();
            if (!d.empty()) ans += ' ';
        }
        return ans;
    }
};

题目5:剑指Offer58.II.左旋转字符串

在这里插入图片描述

解法一:字符串切分与拼接

解题思路:
获取str[n:] 和 str[:n]子串,目标串target = str[:n] + str[n:];

class Solution {
public:
	string reverseLeftWords(string s, int n) {
		string str1 = s.substr(0, n);              //str[:n]
		string str2 = s.substr(n, s.size() - n);   //str[n:] 
		string newstr = str2 + str1;                
		return newstr;
	}
};

解法二:翻转

解题思路:
通过局部翻转+整体翻转达到左旋转的目的,不需要定义新的字符串,完全在原字符串上操作

首先翻转str[:n]子串,其次翻转str[n:]子串,最后翻转str.
在这里插入图片描述

class Solution {
public:
	string reverseLeftWords(string s, int n) {
		reverse(s.begin(), s.begin() + n);       //翻转区间前n的子串
		reverse(s.begin() + n, s.end());         //翻转区间n到末尾的子串
		reverse(s.begin(), s.end());             //翻转整个字符串
		return s;
	}
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值