这一章节我们来讨论一下IT企业面试题:字符串旋转(旋转字母或者单词)。
题目:
将字符串"abcdef"旋转成“defabc”
或者
将字符串"i am a student."旋转成"student. a am i"
而且在上面的题目里面还会加上不能够使用库函数的限制,我们下面将讨论解题的思路以及具体的代码。
1.思路
(1)暴力解法
就是一个字符一个字符的往后扔
(2)分部法
将不旋转部分和旋转部分分开来处理,先各自反转,再整体反转
(3)使用stack特性来处理
对于第一个题目我们可以使用第一第二种思路来处理,而第三种思路是在全部反转的时候更加出彩(如果是某几个旋转,第三种思路就会出现很多麻烦的处理,在这里不推荐使用)
2.具体代码
(1)下面的代码解题:将字符串"abcdef"旋转成“defabc”
package com.ray.datastructure.ch01.topic_1_1; public class ReverseString_1 { private static String FirstCharToEnd(String source) { char[] charArray = source.toCharArray(); char firstLetter = charArray[0]; for (int i = 1; i < source.length(); i++) { charArray[i - 1] = charArray[i]; } charArray[charArray.length - 1] = firstLetter; return new String(charArray); } public static String someCharsToEnd(String source, int countOfChar) { for (int i = 0; i < countOfChar; i++) { source = FirstCharToEnd(source); } return source; } public static void main(String[] args) { String source = "abcdef"; System.out.println(someCharsToEnd(source, 3)); } }
测试输出:
defabc
上面是暴力解法,一个一个字符往后扔,因此造成时间复杂度是O(m*n)相对来说性能较差,当然,如果在笔试比较紧张的前提下,这个也算一个答案
(2)下面的代码解题:将字符串"abcdef"旋转成“defabc”
package com.ray.datastructure.ch01.topic_1_1; public class ReverseString_2 { private static String reverse(String source, int start, int end) { char[] charArray = source.toCharArray(); while (start < end) { char temp = charArray[start]; charArray[start++] = charArray[end]; charArray[end--] = temp; } return new String(charArray); } public static String reverse(String source, int pos) { if (pos > source.length()) { return "error:post is bigger than source‘s length"; } source = reverse(source, 0, pos - 1); source = reverse(source, pos, source.length() - 1); source = reverse(source, 0, source.length() - 1); return source; } public static void main(String[] args) { String source = "abcdef"; System.out.println(reverse(source, 3)); } }
测试输出:
defabc
上面的代码使用了分部法,首先把字符串看成两部分,一部分是需要移动的部分,就是上面的“abc”,另一部分是不需要移动的部分“def”,第二是把这两部分各自反转,变成“cba””fed“,现在返回的字符串是”cbafed“,第三是把”cbafed“这一个字符串整个反转,就变成了“defabc”了,这样的算法,时间复杂度变成了O(n)
(3)下面的代码解题:将字符串"i am a student."旋转成"student. a am i"
根据题目所给出的例子,我们这里应该是单词的调换,因此,就不再像上面的每一个字符的旋转
package com.ray.datastructure.ch01.topic_1_1; public class ReverseString_3 { public static String reverse(String source, String regex, int start, int end) { String[] strArray = source.split(regex); while (start < end) { String temp = strArray[start]; strArray[start++] = strArray[end]; strArray[end--] = temp; } String rtnStr = ""; for (int i = 0; i < strArray.length; i++) { rtnStr += strArray[i] + regex; } return rtnStr.trim(); } public static void main(String[] args) { String source = "i am a student.";// student. a am i String regex = " "; System.out.println(reverse(source, regex, 0, source.split(regex).length - 1)); } }
测试输出:
student. a am i
从通用性来说,上面的这种方式比较好,因为它可以自定义调换的单词,暂时来说是最优实现
(4)下面的代码解题:将字符串"i am a student."旋转成"student. a am i"
对于这一题,我们如果允许使用库函数,可以引入栈的特性
package com.ray.datastructure.ch01.topic_1_1; import java.util.Stack; public class ReverseString_4 { public static String reverse(String source, String regex) { String[] strArray = source.split(regex); Stack<String> stack = new Stack<String>(); for (String item : strArray) { stack.push(item); } String rtnStr = ""; while (!stack.isEmpty()) { rtnStr += stack.pop() + regex; } return rtnStr.trim(); } public static void main(String[] args) { String source = "i am a student.";// student. a am i String regex = " "; System.out.println(reverse(source, regex)); } }
测试输出:
student. a am i
上面的代码利用栈的先进后出的特性来实现题目
但是这里有局限性,它只是在全部旋转的前提下才好使,如果像上面的那种局部也可以调转的情况,就不推荐使用。
总结:这一章节注意结束了字符串反转(旋转字母或者单词)的几种方法。