1.字符串介绍
字符串不是一种数据结构,但是因为其特殊性,其题目需要一些额外的处理策略,比如字符串的匹配,反转等都需要特别考虑。另外字符串有一些基础的工具类,如果我们熟悉的话,可以直接用,反之会特别麻烦。例如如果我们知道StringTokenizer类,那在很多单词拆分,组合等问题上可以非常轻松处理。再比如StringBuffer的charAt()方法,如果不知道的话,解题会寸步难行。
字符串的内容其实非常多的,涉及的题目有的很简单,有的特别难。比较难的题目主要体现在两个方面,一个是匹配相关的问题,暴力搜索效率低,所以产生了很多专门的算法,例如Robin-Karp匹配算法,基于有限自动机的字符串匹配算法,KMP算法,Boyce-Moore算法,后缀树等等,这些方法如果不单独学习,不可能在面试的时候想出来的。另外的一些题目是需要使用动态规划等思想来解决,例如最长递增子序列等等。
我们这里还是梳理一些基本的算法,比较难的问题,我们后面再说。
2. 给定一段文字,寻找出现次数最多的词
给定一段文字,设计一个算法来寻找出现次数最多的词,若段落在不断滚动,也就是一些词消失,一些词仍然存在,还有一些新词出现。寻找当前出现次数最多的词。
这个是典型的流数据下的搜索,这种情况只能用队和优先队列来做。这种题目一般说清楚思路就行了,不需要手写实现。在网上找到一段不错的描述。直接贴过来吧。
3.字符串反转相关问题
反转是个非常常见的问题,数组、链表、数字、字符串等都有反转的问题,难易和实现方法各不一样,我们现在看一下字符串的。
如果字符串是可以编辑的,可以这么写:
public static StringBuffer reverseString(StringBuffer str) {
char temp;
if (str == null) {
return null;
}
int start = 0, end = str.length() - 1;
for (start = 0; start < end; start++, end--) {
temp = str.charAt(start);
str.setCharAt(start, str.charAt(end));
str.setCharAt(end, temp);
}
return str;
}
public static void main(String[] args) {
StringBuffer stringBuffer = new StringBuffer("abcdefg");
System.out.println(reverseString(stringBuffer));
}
测试结果:
这个题目本身不难,但是在面试的时候很难完全写对,首先是空的判断,其次是要记住字符串的这几个方法,如果完全用数组来做,会麻烦很多。
4.如果不使用临时变量能实现字符串反转吗
如果上面的很漂亮的实现了,面试官可能给加个餐,如何不使用临时变量,如果仍然写出来了,我估计面试官肯定想留你了。
可以,可以使用XOR逻辑运算来实现变量的交换,这是有一点难度的。
public static StringBuffer reverseString2(StringBuffer str) {
int end = str.length() - 1;
int start = 0;
while (start < end) {
str.setCharAt(start, (char) (str.charAt(start) ^ str.charAt(end)));
str.setCharAt(end, (char) (str.charAt(end) ^ str.charAt(start)));
str.setCharAt(start, (char) (str.charAt(start) ^ str.charAt(end)));
++start;
--end;
}
return str;
}
5.在上面的基础上,给出一个反转给定句子中单词的算法
例如,输入“dang Shang CTO ying qu bai fu mei”,输出"mei fu bai qu ying CTO Shang dang"
解答:这个好像有赞考过,其他不清楚。从句子的开头开始,不断反转各个单词。假设 空格“ ” 就是单词的分隔符。
在解答之前我们先学一个特殊的String类StringTokenizer。
Java StringTokenizer 属于 java.util 包,用于分隔字符串。
StringTokenizer 构造方法:
-
1. StringTokenizer(String str) :构造一个用来解析 str 的 StringTokenizer 对象。java 默认的分隔符是空格("")、制表符(\t)、换行符(\n)、回车符(\r)。
-
2. StringTokenizer(String str, String delim) :构造一个用来解析 str 的 StringTokenizer 对象,并提供一个指定的分隔符。
-
3. StringTokenizer(String str, String delim, boolean returnDelims) :构造一个用来解析 str 的 StringTokenizer 对象,并提供一个指定的分隔符,同时,指定是否返回分隔符。
StringTokenizer 常用方法:
-
1. int countTokens():返回nextToken方法被调用的次数。
-
2. boolean hasMoreTokens():返回是否还有分隔符。
-
3. boolean hasMoreElements():判断枚举 (Enumeration) 对象中是否还有数据。
-
4. String nextToken():返回从当前位置到下一个分隔符的字符串。
-
5. Object nextElement():返回枚举 (Enumeration) 对象的下一个元素。
-
6. String nextToken(String delim):与 4 类似,以指定的分隔符返回结果。
例子
import java.util.*;
public class Main
{
public static void main(String[] args)
{
String str = "ali,google,taobao,facebook,meituan";
// 以 , 号为分隔符来分隔字符串
StringTokenizer st=new StringTokenizer(str,",");
while(st.hasMoreTokens()) {
System.out.println(st.nextToken());
}
}
}
输出结果为:
ali
google
taobao
facebook
meituan
如果我们知道这个类,解决问题起来就非常方便了:
public static void reversingSentence(String strLine) {
StringTokenizer st = new StringTokenizer(strLine, " ");
String strReverseLine = "";
while (st.hasMoreElements()) {
strReverseLine = st.nextToken() + " " + strReverseLine;
}
System.out.println("result is :" + strReverseLine);
}
测试一下:
String s = "dang Shang CTO ying qu bai fu mei";
reversingSentence(s);
输出结果为:
6.给定串“ABCCBCBA”,设计一个算法,可以不断移除相同的相邻字符
例如ABCCBCBA->“ABBCBA”->"ACBA"。
解答:首先,需要检查给定的字符串是否存在相同的字符对,如果存在就删除,然后检查下一个和前一个字符,继续删除置顶只到达串首或者串尾或者找不到相同字符串时就停止。
public static void removeParis(char[] str, int len) {
int j = 0;
for (int i = 1; i <= len; i++) {
while ((str[i] == str[j]) && (j >= 0)) {
i++;
j--;
}
str[++j] = str[i];
}
for (int i=0 ;i<=j;i++) {
System.out.print(str[i]+" ");
}
}
测试一下:
String pars = "ABCCBCBA";
removeParis(pars.toCharArray(), pars.toCharArray().length - 1);
字符串的问题还有很多,我们后面将回溯、动态规划和贪心学完之后再用一个更加详细的专题来分析字符串的问题。