题目
反转字符串
编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 s 的形式给出。
不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。
public void reverseString(char[] s) {
for(int i=0;i<s.length/2;i++){
char temp=s[i];
s[i]=s[s.length-1-i];
s[s.length-1-i]=temp;
}
}
该题的交换两个元素还有另外一种写法:
s[i] ^= s[j];
s[j] ^= s[i];
s[i] ^= s[j];
通过位运算的方式
541. 反转字符串 II
给定一个字符串 s 和一个整数 k,从字符串开头算起,每计数至 2k 个字符,就反转这 2k 字符中的前 k 个字符。
如果剩余字符少于 k 个,则将剩余字符全部反转。
如果剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符,其余字符保持原样。
首先写一个反转字符串的函数reverse(String s,int k)
public static String reverse(String s,int k){
StringBuilder sb=new StringBuilder();
for(int i=s.length()-1;i>=0;i--){
sb.append(s.charAt(i));
}
return sb.toString();
}
此时目的是将传来的参数s全部按照s的长度进行反转,由于string类型不可修改,因此重新返回一个string类型的对象。
此时完成函数的主体部分,使用递归的方式来计算反转字符串,先判断字符串长度,大于2k则先将前k进行翻转,k-2k保持原状,2k后面的再调用该函数
public static String reverseStr(String s, int k) {
int size=s.length();
if(size<k){
return reverse(s,k);
}else if(size>=k&&size<2*k){
return reverse(s.substring(0,k),k)+s.substring(k);
}else return reverse(s.substring(0,k),k)+s.substring(k,2*k)+reverseStr(s.substring(2*k),k);
}
替换空格
请实现一个函数,把字符串 s 中的每个空格替换成"%20"。
这题最简单的实现方式就是使用库函数调用replaceAll的方式进行
但是要做到极致就尽量少使用额外的空间,可以使用双指针法,第一个指针指向重新定向长度的数组,第二个指针指向原指针的末尾,从后往前进行执行。
// return s.replaceAll(" ","%20");
if(s==null||s.length()==0)return s;
StringBuilder sb=new StringBuilder();
for(int i=0;i<s.length();i++){
if(s.charAt(i)==' '){
sb.append(" ");
}
}
if(sb.length()==0){
return s;//说明没有空格
}
int left=s.length()-1;
s+=sb.toString();
char[] str=s.toCharArray();
int right=s.length()-1;
while(left>=0){
if(s.charAt(left)==' '){
str[right--]='0';
str[right--]='2';
str[right]='%';
}else{
str[right]=s.charAt(left);
}
right--;
left--;
}
return new String(str);
}
151. 反转字符串中的单词
给你一个字符串 s ,请你反转字符串中 单词 的顺序。
单词 是由非空格字符组成的字符串。s 中使用至少一个空格将字符串中的 单词 分隔开。
返回 单词 顺序颠倒且 单词 之间用单个空格连接的结果字符串。
注意:输入字符串 s中可能会存在前导空格、尾随空格或者单词间的多个空格。返回的结果字符串中,单词间应当仅用单个空格分隔,且不包含任何额外的空格。
- 我的思路是使用双指针的方式,从后往前遍历,然后分以下情形,如果left是" ",此时判断是不是left==right,如果是,说明中间不存在字符串,然后直接left++;right++;如果并不是相等,就说明中间存在一个word,此时找到word的首尾范围,substring(left+1,right+1),一旦left不是“ ”,又存在两种情形,一种是left是0,说明已经形成了一个word,如果不是,那么left–。
public String reverseWords(String s) {
int left=s.length()-1;int right=s.length()-1;
StringBuilder sb=new StringBuilder();
while(left>=0){
if(s.charAt(left)!=' '){
if(left==0){
if(sb.length()!=0){
sb.append(" ");
}
sb.append(s.substring(left,right+1));
}left--;
}else{
if(left==right){
left--;
right--;
}else{
String m=s.substring(left+1,right+1);
if(sb.length()!=0){
sb.append(" ");
}
sb.append(m);
left--;
right=left;
}
}
}
return sb.toString();
时间复杂度为O(n);
而同时提高难度,如果空间复杂度控制在O(1),那么就不能有额外的空间,只能进行原地操作。思路为,先将字符串中的多余空格删除,再将字符串翻转,再将其中的单词翻转,就能形成正确的答案。
剑指 Offer 58 - II. 左旋转字符串
给你一个字符串 s ,请你反转字符串中 单词 的顺序。
单词 是由非空格字符组成的字符串。s 中使用至少一个空格将字符串中的 单词 分隔开。
返回 单词 顺序颠倒且 单词 之间用单个空格连接的结果字符串。
注意:输入字符串 s中可能会存在前导空格、尾随空格或者单词间的多个空格。返回的结果字符串中,单词间应当仅用单个空格分隔,且不包含任何额外的空格。
这道题目也非常类似,依然可以通过局部反转+整体反转 达到左旋转的目的。
具体步骤为:
反转区间为前n的子串
反转区间为n到末尾的子串
反转整个字符串
public String reverseLeftWords(String s, int n) {
StringBuilder sb=new StringBuilder();
for(int i=0;i<s.length();i++){
int count=(i+2)%s.length();
sb.append(s.charAt(count));
}
return sb.toString();
}