-
【题目:翻转字符串】
给定一英文句子,在单词间做逆序调整,单词内的字符不变。 -
【举例】
eg1. you love code. ——> code. love you -
【思路】
(1) 整体逆序:you love code. ——> .edoc evol uoy(2) 遍历锁定每个单词 :以空格分隔单词, , ,分别为记录每个单词位置的左右游标,其中(下面的赋值请画图理解),
(3) 每个单词逆序:.edoc evol uoy ——> code. love you
其中,逆序函数,reverse 思路: 首尾互换,次首尾互换…所以,该函数的参数中需要增加左右游标,begin,end,记录当前互换的位置信息。 -
【代码】
//逆转字符串
public void reverse( char[] chas, int begin, int end )
{
char temp = 0;//char型变量0表示空字符
while( begin < end )
{
//字符互换
temp = chas[begin];
chas[begin] = chas[end];
chas[end] = temp;
//移动左右游标
begin++;
end--;
}
}
//逆转句子,单词间逆序
public void rotateSentence( char[] chas )
{
if( chas == null || chas.length == 0 )
{
return;
}
reverse( chas, 0, chas.length-1 );
int l = -1;
int r = -1;
for( int i = 0; i < chas.length; i++ )
{
//尚未遇到空格,则确定当前单词的左右游标
if( chas[i] != ' ' )
{
l = ( ( i == 0 ) || ( chas[i-1] == ' ' ) ? i : l );
r = ( ( i == chas.length-1 ) || ( chas[i+1] == ' ') ? i : r );
}
//当前位置字符为空格
//如果有单词,将之前找到的单词逆置
if( l != -1 && r != -1 )
{
reverse( chas, l, r );
l = -1;
r = -1;
}
}
}
- 【时间复杂度】
O(n) - 【空间复杂度】
额外的空间复杂度为O(1) - 【检查】
考虑代码中是否有越界情况
考虑输入为空的情况,针对字符串、字符数组,特殊考虑null和空字符串""的情况,具体说明见下面的代码,所以才会有上面的判断代码: chas == null || chas.length == 0。
char[] chas1 = null;//null不能判断长度,chas1.length会抛出NullPointerException异常
String str = "";
char[] chas2 = str.toCharArray();//""空字符的字符数组长度为0
System.out.println(chas1==null?1:2);
System.out.println(chas2.length);
输出结果分别为:1 和 0
- 【测试用例】
功能测试:多个字符句子,单个单词的句子
特殊字符测试:null,空字符"",只有一个空格的字符" " - 【变形一:左旋转字符串】:
给定一个整数n,将大小为n的左半边字符转移到字符串的尾部。 - 【举例】
eg1. 字符串:you love code. 整数:2 ——> u love code.yo - 【思路】
一个比较巧妙的方法
(1) 将原字符串按照整数值,分为左右两部分: yo和u love code.
(2) 分别将左右两部分字符串逆序操作:oy 和.edoc evol u
(3) 再对整体字符串进行逆序操作:u love code.yo
其中,逆序操作reverse函数同上一道题。 - 【代码】
//左旋字符串
public void rotate1( char[] chas, int n )
{
if( chas == null || n <= 0 || n >= chas.length )
{
return;
}
reverse( chas, 0, n-1 );
reverse( chas, n,chas.length-1 );
reverse( chas, 0, chas.length-1 );
}
- 【时间复杂度】
O(n) - 【空间复杂度】
额外的空间复杂度为O(1) - 【检查】
考虑代码中是否有越界情况
考虑输入为空的情况 - 【测试用例】
功能测试:将字符串左旋0个,1个,n-1个,n个,n+1个字符
特殊字符测试:null,空字符"" - 【变形二】:
翻转中间由各种符号隔开的字符串。 - 【举例】
eg1. 字符串:you;love;code; 分隔符:; ——> uoy;evol;edoc; - 【思路】
(一) 思路一:与上面例题思路基本相同
(1) 遍历锁定每个单词 :以指定分隔符分隔单词, , ,分别为记录每个单词位置的左右游标
(2) 对每个单词进行逆序操作
(二) 思路二:采用Java内特有的处理字符串的函数
(1) 指定分隔符为delim:StringTokenizer( String str, String delim )
(2) 判断字符串中是否还有分隔符:boolean hasMoreToken( String delim)
(3) 只要还有分隔符,就取从当前位置到下一个分隔符之前的字符串:String nextToken( String delim )
(4) 逆置上一步取得的字符串,输出,同时输出分隔符
(5) 重复(3)(4)的操作,直至没有分隔符 - 【代码】
(一)
//逆转句子,单词内逆序
public void rotateSentence2( char[] chas, char delim )
{
if( chas == null || chas.length == 0 )
{
return;
}
int l = -1;
int r = -1;
for( int i = 0; i < chas.length; i++ )
{
//尚未遇到分隔符delim,则确定当前单词的左右游标
if( chas[i] != delim )
{
l = ( ( i == 0 ) || ( chas[i-1] == delim ) ? i : l );
r = ( ( i == chas.length-1 ) || ( chas[i+1] == delim) ? i : r );
}
//当前位置字符为delim
//如果有单词,将之前找到的单词逆置
else
{
reverse(chas, l, r);
}
}
}
(二)
import java.util.Scanner;
import java.util.StringTokenizer;
public class Rotate
{
public static void main( String[] args )
{
Scanner sc = new Scanner( System.in );
System.out.println("请输入字符串:");
String str = sc.nextLine();
StringTokenizer st = new StringTokenizer( str, ";");
while( st.hasMoreTokens() )
{
String streverse = new StringBuffer( st.nextToken() ).reverse().toString();
System.out.print( streverse );
System.out.print( ";" );
}
}
}
思路(二),给出了完整的可运行代码,大家可以自行体会一下字符串的读取操作Scanner的用法;理解一下String,StingBuffer的区别,String类是字符串常量,StringBuffer是字符串变量,可扩充,可修改,而Java中自带的reverse函数是将一个输入流倒序输出,不可以用于字符串上。变形二的其他细节本文就不再赘述了。
(文中题源摘自剑指offer,程序员代码面试指南,牛客网面经,思路均为作者原创总结,文中如有错误,烦请各位读者指出,让我们共同进步,一起成长!)