代码随想录算法训练营第八天 | LeetCode344.反转字符串 | LeetCode541.反转字符串2 | 剑指offer05.替换空格 | LeetCode151.翻转字符串里的单词 | 剑指offer58-2.左旋转字符串
344.反转字符串
题目:编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 s 的形式给出。
不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。
题目链接
示例 1:
输入:s = [“h”,“e”,“l”,“l”,“o”]
输出:[“o”,“l”,“l”,“e”,“h”]
分析加代码
比较简单,定义两指针,分别指向两端,交替赋值即可
class Solution {
public void reverseString(char[] s) {
int l=0;
int r=s.length-1;
while(l<r){
char temp=s [l];
s[l]=s[r];
s [r]=temp;
l++;
r--;
}
}
}
541.反转字符串2
题目:给定一个字符串 s 和一个整数 k,从字符串开头算起,每计数至 2k 个字符,就反转这 2k 字符中的前 k 个字符。
如果剩余字符少于 k 个,则将剩余字符全部反转。
如果剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符,其余字符保持原样。
示例 1:
输入:s = “abcdefg”, k = 2
输出:“bacdfeg”
题目链接
分析加代码
(记得在遍历字符串的过程中,只要让 i += (2 * k), i 每次移动 2 * k 就可以了,然后判断是否需要有反转的区间)因为要找的也就是每2 * k 区间的起点,这样写,程序会高效很多
以下两种方法相似,认真理解:
class Solution {
public String reverseStr(String s, int k) {
StringBuffer res =new StringBuffer();//StringBuffer类是动态字符串数组.
int l=0;//左指针
int length=s.length();//右指针,注意length()表示求字符串对象的长度,而length表示属性,表示求数组长度
while(l<length){
StringBuffer temp=new StringBuffer();//为什么又定义一个动态数组,因为该数组是用来存储反转的数组,题目要求有一部分是不需要反转的,所以你要定义一个中间身份的动态数组,然后再存入到真正目标数组.
int firstk=((l+k)>length) ? length : l+k; //不难,好好理解
int second2k=((l+(2*k))>length) ? length : l+(2*k);
temp.append(s.substring(l,firstk));//append()方法表示将指定的字符串追加到此字符序列(属于stringbuffer类里)。substring(intbeginIndex,intendIndex),表示截取父字符串的某一部分。
res.append(temp.reverse());//reverse()方法表示反转该字符序列(也属于stringbuffer类)
if(firstk<second2k){ //firstk 到second2k这段长度肯定大于等于k,所以该条件下字符保持原样(题目要求)
res.append(s.substring(firstk,second2k));
}
l+=2*k;// (注意l每次移动2*k步,因为隔2k个才能移动前k个。这也就解释了为什么找到k与2k位置)
}
return res.toString();
}
}
class Solution {
public String reverseStr(String s, int k) {
char[] ch = s.toCharArray();
// 1. 每隔 2k 个字符的前 k 个字符进行反转
for (int i = 0; i< ch.length; i += 2 * k) {
// 2. 剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符
if (i + k <= ch.length) {
reverse(ch, i, i + k -1);
continue;
}
// 3. 剩余字符少于 k 个,则将剩余字符全部反转
reverse(ch, i, ch.length - 1);
}
return new String(ch);
}
// 定义翻转函数
public void reverse(char[] ch, int i, int j) {
for (; i < j; i++, j--) {
char temp = ch[i];
ch[i] = ch[j];
ch[j] = temp;
}
}
}
剑指offer05.替换空格
题目:请实现一个函数,把字符串 s 中的每个空格替换成"%20"。
示例 1:
输入:s = “We are happy.”
输出:“We%20are%20happy.”
题目链接
分析加代码
class Solution {
public String replaceSpace(String s) {
if(s==null){
return null;
}
StringBuffer str=new StringBuffer();
for (int i=0;i<s.length();i++){
if(s.charAt(i)==' '){//只是找出s字符串间的空格,如果哪一块有
str.append("%20");//就给str里面填入个%20.此过程并没有把s的空格给str,而是检验到s若有空格,则给atr里面加个%20.
}else {
str.append(s.charAt(i));//说明没有空格,原型返回给str
}
}
return str.toString();
}
}
151.翻转字符串里的单词
题目:给你一个字符串 s ,请你反转字符串中 单词 的顺序。
单词 是由非空格字符组成的字符串。s 中使用至少一个空格将字符串中的 单词 分隔开。
返回 单词 顺序颠倒且 单词 之间用单个空格连接的结果字符串。
注意:输入字符串 s中可能会存在前导空格、尾随空格或者单词间的多个空格。返回的结果字符串中,单词间应当仅用单个空格分隔,且不包含任何额外的空格。
示例 1:
输入:s = “the sky is blue”
输出:"blue is sky the
题目链接
分析加代码
class Solution {
public String reverseWords(String s) {
char[] charArray=s.toCharArray();//tocharArray():将字符串对象中的字符转换为一个字符数组
int left=0,right=s.length()-1;//定义两指针。分别指向两端
// 清除字符串两边的空格
// 清除左边
while(charArray[left]==' '){ //数组中若是有空格,则跳过即删除
left++;
}
// 清除右边
while(charArray[right]==' '){ //同理
right--;
}
StringBuilder sb=new StringBuilder(); //定义一个动态数组,来存放单词
// 开始添加单词
while(left<=right){
int index=right;//定义一个index使他与right指同一位置
// index 向左遍历找到第一个空格,找到第一个空格,说明第一个单词就找到了即index后面是第一个单词(index+1)
while(index>=left&&charArray[index]!=' '){ //该条件若是不成立说明找到了第一个完整单词
index--;
}
// 现在 index 已经找到第一个空格,i=index+1 后移到字符串出现的位置
for(int i=index+1;i<=right;i++){ //从第一个字母(index+1)开始,一一遍历从而把完整的第一个单词添加到sb中
sb.append(charArray[i]); // 添加字符串到定义的动态数组里即sb中
}
if(index>left) sb.append(' ');//题目要求是单词间存在空格,则定义的数组就要提前归整好格式,即把空格也要添加进去。注意添加的这个单词不能是最后一个单词,如果字符串本身只有一个单词,添加空格就没有意义。
while(index>=left&&charArray[index]==' '){// 使用 index 指针 跳过中间可能出现的空格
index--;
}
right=index; // 把 right 放到下一个单词出现的位置,继续按以上操作循环
}
return sb.toString();
}
}
剑指offer58-2.左旋转字符串
题目:字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。请定义一个函数实现字符串左旋转操作的功能。比如,输入字符串"abcdefg"和数字2,该函数将返回左旋转两位得到的结果"cdefgab"。
示例 1:
输入: s = “abcdefg”, k = 2
输出: “cdefgab”
题目链接
分析加代码
class Solution {
public String reverseLeftWords(String s, int n) {
//解法一:空间复杂度:O(1)。用原始数组来进行反转操作
//思路为:先整个字符串反转,再反转前面的,最后反转后面 n 个
char[] chars = s.toCharArray();
reverse(chars, 0, chars.length - 1);
reverse(chars, 0, chars.length - 1 - n);
reverse(chars, chars.length - n, chars.length - 1);
return new String(chars);
}
public void reverse(char[] chars, int left, int right) {//构造的reverse函数
while (left < right) {
char temp=chars[left];
chars[left]=chars[right];
chars[right]=temp;
left++;
right--;
}
}
}
class Solution {
public String reverseLeftWords(String s, int n) {
//方法二 遍历拼接
StringBuffer ans =new StringBuffer();
int r=s.length();
for (int i=n;i<s.length();i++){
ans.append(s.charAt(i));
}
for(int i=0;i<n;i++){
ans.append(s.charAt(i));
}
return ans.toString();
}
}
class Solution {
public String reverseLeftWords(String s, int n) {
//方法三 采用substring()方法
return s.substring(n,s.length()) + s.substring(0,n);
}
}
总结:解题不要仅仅限于只把题写出来就好,在具体开发中或者面试中,还要考虑时间复杂度,库函数虽然好用,但时间复杂度也会随之变高,不利,所以巧用方法,体会编程思想,关键部分如果可以用库函数解决,就勿用库函数。