目录
字符串part1:
LeetCode344、反转字符串
代码
class Solution {
public void reverseString(char[] s) {
for (int i = 0, j = (s.length-1); i < (s.length/2); i++, j--){
if (i < j){
char temp = s[j];
s[j] = s[i];
s[i] = temp;
}
}
}
}
两个指针从两头移动到中间,每移动一次交换位置
LeetCode541、反转字符串2
代码
class Solution {
public String reverseStr(String s, int k) {
char[] array = s.toCharArray();
int times = (array.length / (2*k)) + 1;
for(int i = 0; i < times; i++){
int left = 2*k*i;
int right = 2*k*i + (k-1);
if (right >= array.length){
right = array.length - 1;
}
while (left < right){
char temp = array[right];
array[right] = array[left];
array[left] = temp;
left++;
right--;
}
}
return String.valueOf(array);
}
}
或
class Solution {
public String reverseStr(String s, int k) {
char[] ch = s.toCharArray();
for(int i = 0;i < ch.length;i += 2 * k){
int start = i;
// 判断尾数够不够k个来取决end指针的位置
int end = Math.min(ch.length - 1,start + k - 1);
while(start < end){
char temp = ch[start];
ch[start] = ch[end];
ch[end] = temp;
start++;
end--;
}
}
return new String(ch);
}
}
两种不同写法的for,一种是遍历2k的次数,一种是遍历字符,每次+=2*k
【知识点】
char[] ch = s.toCharArray();
return String.valueOf(array);
//或
return new String(array);
剑指offer05、替换空格
思路
若将字符串转为数组操作,一个空格对应’%20’三个字符,则肯定要给数组扩容。
定义两个指针,从后往前填充,像追及问题,追的路程是空格个数*2,两指针相遇之时说明所有因为空格导致的路程都追上来了,则前面就没有空格了。又因为再相遇之前,后面的指针一直没追上前面的指针,所以不存在有字符没有保存就被覆盖了的问题。
public class StringOffer05 {
//方法1
public String replaceSpace(String s) {
int originLength = s.length();
int num = 0;
for (int i = 0; i < s.length(); i++){
if (s.charAt(i) == ' '){
num++;
}
}
for (int i = 0; i < num; i++){
s = s.concat(" ");
}
char[] array = s.toCharArray();
for (int i = (originLength-1), j = (array.length-1); i >= 0; i--, j--){
if (i == j){
break;
}
if (array[i] == ' '){
array[j] = '0';
array[j-1] = '2';
array[j-2] = '%';
j -= 2;
}else {
array[j] = array[i];
}
}
return String.valueOf(array);
}
//方法2
public String replaceSpace(String s){
StringBuilder str = new StringBuilder();
for (int i = 0; i < s.length(); i++){
if (s.charAt(i) == ' '){
str.append("%20");
}else {
str.append(s.charAt(i));
}
}
return str.toString();
}
}
【知识点】
- StringBuilder是可变的,append函数接字符串,字符,数字都可以
- StringBuilder转String用toString()函数
- 方法1中之所以要先求出来num,是因为如果在遍历s的过程中,就
s.concat(" ")
的话,s的长度则会不断变化,则会陷入死循环
LeetCode151、反转字符串中的单词
调用库函数的思路:
先split,再reverse,再concat/join
Java用split分割含一个或多个空格的字符串(正则表达式)
时间复杂度O(n)思路:
- 去空格,我的第一种写法是把所有空格一起考虑了,比较难想;代码随想录里给的代码是把首尾的空格与中间的空格分开考虑,比较好操作
- 整体反转:hello world变成dlrow olleh
- 单个单词反转:dlrow olleh变成world hello
- 2和3在实现的时候,我的写法是各写各的,代码随想录里给的代码是可以用同一个函数,定义输入字符串,反转开始字符和反转结束字符就可以。
代码
class Solution {
public String reverseWords(String s) {
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < s.length(); i++){
if (s.charAt(i) != ' '){
stringBuilder.append(s.charAt(i));
}
if ((s.charAt(i) == ' ') && (i-1 >=0) && (s.charAt(i-1) != ' ')){
int temp = i;
while (i < s.length()){
//这里要注意,第一遍写的时候在这里出错了,少考虑了末尾有多个空格的情况。
//只有在判断完这个空格后还有字符的时候,才能append空格。
if (s.charAt(i) != ' '){
stringBuilder.append(' ');
i = temp;
break;
}
i++;
}
}
}
s = stringBuilder.toString();
StringBuilder reverseAll = new StringBuilder();
for (int i = (s.length()-1); i >=0; i--){
reverseAll.append(s.charAt(i));
}
s = reverseAll.toString();
char[] finalArray = s.toCharArray();
for (int i = 0; i < s.length(); ){
if (finalArray[i] == ' '){
i++;
continue;
}else {
int left = i;
int length = 0;
while ((i < s.length()) && (finalArray[i] != ' ')){
i++;
length++;
}
int right = i - 1;
while (left < right){
char temp = finalArray[left];
finalArray[left] = finalArray[right];
finalArray[right] = temp;
left++;
right--;
}
}
}
return String.valueOf(finalArray);
}
}
去空格的另外一种思路:把首尾的空格与中间的空格分开考虑
private StringBuilder removeSpace(String s) {
// System.out.println("ReverseWords.removeSpace() called with: s = [" + s + "]");
int start = 0;
int end = s.length() - 1;
while (s.charAt(start) == ' ') start++;
while (s.charAt(end) == ' ') end--;
StringBuilder sb = new StringBuilder();
while (start <= end) {
char c = s.charAt(start);
if (c != ' ' || sb.charAt(sb.length() - 1) != ' ') {
sb.append(c);
}
start++;
}
// System.out.println("ReverseWords.removeSpace returned: sb = [" + sb + "]");
return sb;
}
反转字符串或是字符串中的单词,用一个函数统一起来
/**
* 反转字符串指定区间[start, end]的字符
*/
public void reverseString(StringBuilder sb, int start, int end) {
// System.out.println("ReverseWords.reverseString() called with: sb = [" + sb + "], start = [" + start + "], end = [" + end + "]");
while (start < end) {
char temp = sb.charAt(start);
sb.setCharAt(start, sb.charAt(end));
sb.setCharAt(end, temp);
start++;
end--;
}
// System.out.println("ReverseWords.reverseString returned: sb = [" + sb + "]");
}
private void reverseEachWord(StringBuilder sb) {
int start = 0;
int end = 1;
int n = sb.length();
while (start < n) {
while (end < n && sb.charAt(end) != ' ') {
end++;
}
reverseString(sb, start, end - 1);
start = end + 1;
end = start + 1;
}
}
【知识点】
char数组里,可以随意给数组里的任何一个元素赋值
对于string,string.charAt(i) = ...
这个语句是不被允许的,因为string是immutable
对于stringbuilder,可以改变其中某个字符的值,方法是stringbuilder.setCharAt(位置,值)
;charAt()
函数是取值,而不是赋值
将string转为stringbuilder:StringBuilder sb=new StringBuilder(s);
将stringbuilder转为string:s = sb.toString();
Offer58、左旋字符串
思路一:
定义两个stringbuilder,遍历字符串,一个stringbuilder存放k之前的,另一个存放k之后的,然后concat两个字符串
代码:
class Solution {
public String reverseLeftWords(String s, int n) {
if (s.equals(null)){return s;}
StringBuilder left = new StringBuilder();
StringBuilder right = new StringBuilder();
for (int i = 0; i < n; i++){
left.append(s.charAt(i));
}
for (int i = n; i < s.length(); i++){
right.append(s.charAt(i));
}
return right.toString().concat(left.toString());
}
}
思路二:
不申请额外空间,只用一个stringbuilder。
定义一个反转方法,先k之前反转,k之后反转,再整体反转:
或者先整体发展,再length-k之前发转,后面的k反转
代码:
class Solution {
public String reverseLeftWords(String s, int n) {
int len=s.length();
StringBuilder sb=new StringBuilder(s);
reverseString(sb,0,n-1);
reverseString(sb,n,len-1);
return sb.reverse().toString();
}
public void reverseString(StringBuilder sb, int start, int end) {
while (start < end) {
char temp = sb.charAt(start);
sb.setCharAt(start, sb.charAt(end));
sb.setCharAt(end, temp);
start++;
end--;
}
}
}
【知识点】
stringbuilder的整体反转操作:sb.reverse()