day8 记录代码随想录
第一题 力扣344. 反转字符串
编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 char[] 的形式给出。
不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。
你可以假设数组中的所有字符都是 ASCII 码表中的可打印字符。
示例 1:
输入:["h","e","l","l","o"]
输出:["o","l","l","e","h"]
示例 2:
输入:["H","a","n","n","a","h"]
输出:["h","a","n","n","a","H"]
题目链接:力扣题目链接
解题思路:
本题很简单,交换头尾字符即可,使用双指针法很容易实现。
代码如下:
class Solution {
public:
void reverseString(vector<char>& s) {
for(int i = 0 ; i < s.size() / 2 ; i++) {
int j = s.size() - i -1;
char tem;
tem = s[i];
s[i] = s[j];
s[j] = tem;
}
}
};
这里介绍一下C++11里的两个库函数:swap和reverse
swap()用来交换两个元素的位置。
reverse()用来翻转参数范围内的元素顺序。
需要注意的是reverse(s.begin(), s.begin() + k),是翻转s的第一个元素到第k-1个元素,不包括k。
第二题 力扣541. 反转字符串II
给定一个字符串 s 和一个整数 k,从字符串开头算起, 每计数至 2k 个字符,就反转这 2k 个字符中的前 k 个字符。
如果剩余字符少于 k 个,则将剩余字符全部反转。
如果剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符,其余字符保持原样。
示例:
输入: s = "abcdefg", k = 2
输出: "bacdfeg"
题目链接:力扣题目链接
解题思路:
本题可以考虑用双指针来做,指针间距为k,翻转两个指针内的字符,然后同时右移2k即可,同时注意右边指针的范围符合条件就可以了。
代码如下:
//双指针
class Solution {
public:
string reverseStr(string s, int k) {
int length = s.size();
int left = 0;
int right = left + k - 1;
while(left < length) {
if(right > length - 1)
right = length - 1;
for (int i = left ; i < (left + right + 1) / 2 ; i++) {
int j = (left + right) - i;
swap(s[i], s[j]);
}
cout<<s<<endl;
left += 2*k;
right += 2*k;
}
return s;
}
};
第三题 卡码网:54.替换数字
给定一个字符串 s,它包含小写字母和数字字符,请编写一个函数,将字符串中的字母字符保持不变,而将每个数字字符替换为number。
例如,对于输入字符串 "a1b2c3",函数应该将其转换为 "anumberbnumbercnumber"。
对于输入字符串 "a5b",函数应该将其转换为 "anumberb"
输入:一个字符串 s,s 仅包含小写字母和数字字符。
输出:打印一个新的字符串,其中每个数字字符都被替换为了number
样例输入:a1b2c3
样例输出:anumberbnumbercnumber
数据范围:1 <= s.length < 10000。
题目链接:卡码网题目链接
解题思路:
本题最简单的做法就是遍历一次s,遇到字母就存到新字符串ns中,遇到数字就存number到ns中,使用 ns += "number" 能快速在ns的末尾添加。
//新建数组
#include <iostream>
#include <string>
using namespace std;
int main() {
string s;
while(cin>>s) {
string ns;
// int k = 0;
for(int i = 0; i < s.size(); i++) {
if(s[i] >= '0' && s[i] <='9') {
//ns += "number";
//ns.append("number");
}
else
ns += s[i];
}
cout<<ns<<endl;
}
return 0;
}
本题使用双指针法可以在一个原数组里面修改:
首先遍历一下字符数组,找出其中数字的个数count
然后将原数组扩充一下,即在尾部加空格,语句:s.resize(s.size() + count * 5 , ' ' )
使用快慢指针 i 和 j , i 从原数组末尾开始, j 从新数组末尾开始,同时向左移动, i 遇到字母 ,则将 s[j] = s[i] ,i遇到数字则将j左边6个换成number
//双指针法
#include <iostream>
#include <string>
using namespace std;
int main() {
string s;
while(cin>>s) {
int count = 0; //存储数字个数
int length = s.size();
int newlength = 0;
for(int i = 0; i<length; i++) {
if( s[i] >= '0' && s[i] <= '9')
count++;
}
s.resize(s.size() + count * 5, ' ');
newlength = s.size();
for (int i = length - 1, j = newlength - 1 ; i >= 0; i--) {
if( s[i] >= '0' && s[i] <= '9' ) {
s[j-5] = 'n';
s[j-4] = 'u';
s[j-3] = 'm';
s[j-2] = 'b';
s[j-1] = 'e';
s[j] = 'r' ;
j -= 5;
}
else
s[j] = s[i];
j--;
}
cout<<s<<endl;
}
return 0;
}
第四题 力扣151.翻转字符串里的单词
给定一个字符串,逐个翻转字符串中的每个单词。
示例 1:
输入: "the sky is blue"
输出: "blue is sky the"
示例 2:
输入: " hello world! "
输出: "world! hello"
解释: 输入字符串可以在前面或者后面包含多余的空格,但是反转后的字符不能包括。
示例 3:
输入: "a good example"
输出: "example good a"
解释: 如果两个单词间有多余的空格,将反转后单词间的空格减少到只含一个。
题目链接:力扣题目链接
解题思路:
本题主要两个要求,第一:删去多余空格,第二:单词翻转。
第一个要求是比较容易实现的:
遍历一遍s,当s[i] 不等于空格时 进入处理,即删去所有空格,判断s[i] 是否等于空格,不等则存入s[slow],同时i++,slow++,当s[i]等于空格了就跳出循环。其中,每次进入循环时,要将s[slow]设置为空格,表示此处为上一格单词的结尾,当slow = 0时忽略这一步操作。
遍历完s以后,即当i = s.size()时跳出循环,此时slow为删去空格后的实际字符串大小。
将s大小重置为slow,语句为:s.resize(slow)。
第二个要求可以分为两步来做:第一步将整个字符串翻转一下,第二步,将每个单词翻转一下
这里可以直接用reverse库函数,也可以自己定义一个reverse。
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]);
}
}
void remove_space(string& s) {
int slow = 0;
for( int i = 0 ; i < s.size() ; i++) {
if( s[i] != ' ') {
if( slow != 0)
s[slow++] = ' ';
while(i< s.size() && s[i] != ' ')
s[slow++] = s[i++];
}
}
s.resize(slow);
}
string reverseWords(string s) {
remove_space(s);
reverse(s, 0, s.size() - 1);
int start = 0;
for(int i = 0; i <= s.size() ; i++) {
if( i == s.size() || s[i] == ' ') {
reverse(s, start, i - 1);
start = i + 1;
}
}
return s;
}
};
另外介绍一个函数erase,可以删除指定位置的元素,并将后面的元素前移,用例:s.erase(s.begin() + i);
第五题 卡码网 55.右旋字符串
字符串的右旋转操作是把字符串尾部的若干个字符转移到字符串的前面。给定一个字符串 s 和一个正整数 k,请编写一个函数,将字符串中的后面 k 个字符移到字符串的前面,实现字符串的右旋转操作。
例如,对于输入字符串 "abcdefg" 和整数 2,函数应该将其转换为 "fgabcde"。
输入:输入共包含两行,第一行为一个正整数 k,代表右旋转的位数。第二行为字符串 s,代表需要旋转的字符串。
输出:输出共一行,为进行了右旋转操作后的字符串。
题目链接:卡码网题目链接
解题思路:
本题如果使用一个新数组是很容易实现的,那么如果需要在原数组里修改呢?
可以看得出来,这是一个循环右移的过程,但是字符串的循环右移是不好实现的。。。
可以参考第四题,使用字符串的翻转来做。
第一步,将所有字符串翻转,那么 f 和 g 就到了最前面,此时为 g f e d c b a
第二步,将 g f 翻转
第三部,将 e d c b a翻转。
代码如下:
#include <iostream>
#include <algorithm>
using namespace std;
int main() {
string s;
int k;
cin >> k;
cin >> s;
reverse(s.begin(), s.end());
reverse(s.begin(), s.begin() + k);
reverse(s.begin() + k, s.end());
cout << s <<endl;
return 0;
}