最近参加某公司二面,出了个算法题“求字符串中第一个出现最少的字符”,一时蒙了,,居然木有想出来,再加上没有熟悉的IDE没手感(真心感觉,敲java需要手感,哈哈可能我还很水)
【方案1】原始方法
(1)申请一个数组,与字符串等长
(2)循环字符串,对每个字符串进行(3)操作
(3)将字符与字符串中的所有字符进行比对(是否包含自身无所谓),并记录出现个数
(4)遍历统计统计结果,求得最少出现的(第一个很简单,使用打擂法很容易排除后面与之相等的情况。)
参考代码如下:
/**
* 原始办法,逐个匹配
*
* @param chars
* @return
*/
private static char function0(char[] chars) {
int arrayResult[] = new int[chars.length];//某个字符出现重复数。默认为0
for (int i = 0; i < chars.length; i++)
for (int j = 0; j < chars.length; j++)
if (chars[j] == chars[i]) arrayResult[i]++;
int num = 0;
for (int i = 1; i < chars.length; i++)
if (arrayResult[num] > arrayResult[i]) {
num = i;
}
return chars[num];
}
看似代码量比较少,,实际运行效率很差的。
【方案2】备忘录法
在原始方法基础上添加备忘录,
(1),申请一个数组,与字符串等长
(2),循环字符串,对每个字符串进行(3)操作
(3),从当前位置的下一个开始,向后匹配,当遇到相同数时停下,将当前字符出现次数加1赋值给改字符(相当于做了一个备忘录),并对当前字符做特殊标记,表示后面还有出现。
参考代码:
/**
* 【1】,申请一个长度为chars.length,用来记录每个字符出现的次数
* 【2】,对chars进行遍历,比对每个字符,统计其出现个数
* 【3】,从当前位置的下一个开始,向后匹配,当遇到相同数时停下,
* 将当前字符出现次数加1赋值给改字符(相当于做了一个备忘录),
* 并对当前字符做特殊标记,表示后面还有出现。
*
* @param chars
* @return
*/
private static char function1(char[] chars) {
int arrayResult[] = new int[chars.length];
for (int i = 0; i < chars.length; i++) {
if (arrayResult[i] < 1) arrayResult[i] = 1;//置为1,,某个字符至少一个
for (int j = i + 1; j < chars.length; j++)
if (chars[j] == chars[i]) {
arrayResult[j] = arrayResult[i] + 1;
arrayResult[i] = -1;//-1标记代表改字符后面还有字符
break;
}
}
int num = 0;
for (int i = 1; i < chars.length; i++)
if (arrayResult[i] > 0 && arrayResult[num] > arrayResult[i]) {
num = i;
}
return chars[num];
}
去掉注释,,代码量也比较少(浓缩就是精华。)
【方案3】
利用hashmap,,把字符依次放入hash表中,如果存在该字符的key,则value++
/**
* 利用hashmap,,把字符依次放入hash表中,如果存在该字符的key,则value++
*
* @param chars
* @return
*/
private static char function2(char[] chars) {
//创建hashmap
Map<Character, Integer> charMap = new HashMap<>();
for (int i = 0; i < chars.length; i++) {
if (charMap.containsKey(chars[i]))
charMap.put(chars[i], charMap.get(chars[i]) + 1);
else
charMap.put(chars[i], 1);
}
int num = 0;
for (int i = 1; i < chars.length; i++)
if (charMap.get(chars[num]) > charMap.get(chars[i])) {
num = i;
}
return chars[num];
}
这个方法,,,算是最容易实现的,,不过借助了库函数(不是很好哦),,玩的是算法。
三种方案对比
【方案1】
比较低端,,几乎没有使用任何优化手段,只是做了简单的匹配。
【方案2】
中高端,使用到了备忘录的方法(类似动态规划),对检索进行优化,很适用于重复率较高的串
【方案3】
巧妙利用库函数,不过算法方面体现的不是很到位,业务代码中使用比较合适(当然自己优化更好)
三种方案运行时间对比。(博主使用 jdk1.8,IDEA2016)
很明显备忘录法优势杠杠的。(原因是测试串重复率很高)
完整测试代码如下
package algorithm_2;
import java.util.HashMap;
import java.util.Map;
/**
* Created by zsl on 2017/8/24.
* 求字符串中第一个出现最少的字符
*/
public class StringFindFirstLess {
public static void main(String[] args) {
String str = "首aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天" +
"aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天" +
"aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天" +
"aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天" +
"aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天" +
"aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天" +
"aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天" +
"aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天" +
"aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天" +
"aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天" +
"aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天" +
"aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天" +
"aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天" +
"aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天" +
"aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天" +
"aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天" +
"aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天" +
"aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天" +
"aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天" +
"aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天" +
"aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天" +
"aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天" +
"aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天" +
"aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天" +
"aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天" +
"aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天" +
"aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天" +
"aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天" +
"aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天" +
"aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天" +
"aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天" +
"aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天" +
"aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天" +
"aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天" +
"aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天" +
"aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天" +
"aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天" +
"aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天" +
"aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天" +
"aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天" +
"aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天" +
"aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天" +
"aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天" +
"aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天" +
"aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天" +
"aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天" +
"aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天" +
"aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天" +
"aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天" +
"aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天" +
"aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天" +
"aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天" +
"aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天" +
"aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天" +
"aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天" +
"aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天aabbccddacd今天尾";
//测试本办法,花费时间
char result = 0;
long start = System.currentTimeMillis();
result = function0(str.toCharArray());
long end = System.currentTimeMillis();
System.out.println("所求字符为:" + result);
System.out.println("【原始方法】运行时间:" + (end - start) + "毫秒");//应该是end - start
//加入备忘录,花费时间
start = System.currentTimeMillis();
result = function1(str.toCharArray());
end = System.currentTimeMillis();
System.out.println("所求字符为:" + result);
System.out.println("【备忘录法】运行时间:" + (end - start) + "毫秒");//应该是end - starti
//使用HashMap,花费时间
start = System.currentTimeMillis();
result = function2(str.toCharArray());
end = System.currentTimeMillis();
System.out.println("所求字符为:" + result);
System.out.println("【HashMap法】运行时间:" + (end - start) + "毫秒");//应该是end - starti
}
/**
* 原始办法,逐个匹配
*
* @param chars
* @return
*/
private static char function0(char[] chars) {
int arrayResult[] = new int[chars.length];//某个字符出现重复数。默认为0
for (int i = 0; i < chars.length; i++)
for (int j = 0; j < chars.length; j++)
if (chars[j] == chars[i]) arrayResult[i]++;
int num = 0;
for (int i = 1; i < chars.length; i++)
if (arrayResult[num] > arrayResult[i]) {
num = i;
}
return chars[num];
}
/**
* 【1】,申请一个长度为chars.length,用来记录每个字符出现的次数
* 【2】,对chars进行遍历,比对每个字符,统计其出现个数
* 【3】,从当前位置的下一个开始,向后匹配,当遇到相同数时停下,
* 将当前字符出现次数加1赋值给改字符(相当于做了一个备忘录),
* 并对当前字符做特殊标记,表示后面还有出现。
*
* @param chars
* @return
*/
private static char function1(char[] chars) {
int arrayResult[] = new int[chars.length];
for (int i = 0; i < chars.length; i++) {
if (arrayResult[i] < 1) arrayResult[i] = 1;//置为1,,某个字符至少一个
for (int j = i + 1; j < chars.length; j++)
if (chars[j] == chars[i]) {
arrayResult[j] = arrayResult[i] + 1;
arrayResult[i] = -1;//-1标记代表改字符后面还有字符
break;
}
}
int num = 0;
for (int i = 1; i < chars.length; i++)
if (arrayResult[i] > 0 && arrayResult[num] > arrayResult[i]) {
num = i;
}
return chars[num];
}
/**
* 利用hashmap,,把字符依次放入hash表中,如果存在该字符的key,则value++
*
* @param chars
* @return
*/
private static char function2(char[] chars) {
//创建hashmap
Map<Character, Integer> charMap = new HashMap<>();
for (int i = 0; i < chars.length; i++) {
if (charMap.containsKey(chars[i]))
charMap.put(chars[i], charMap.get(chars[i]) + 1);
else
charMap.put(chars[i], 1);
}
int num = 0;
for (int i = 1; i < chars.length; i++)
if (charMap.get(chars[num]) > charMap.get(chars[i])) {
num = i;
}
return chars[num];
}
}