第一次出现一次的字符
2015-08-29
次访问
剑指offer面试题系列
题目
在字符串中找出第一个只出现一次的字符。如输入“abaccdeff”,则输出b。
思路
如果按照常规的思路则为设立一个辅助数组,里面存放所有扫描过的字符的次数,则这种算法的时间复杂度为O(n^2).
因为每一次遍历到新的字符,都要在辅助数组里面扫描一遍,如果没有,则加上此字符,如果有则统计次数累加。
所以这样是不太满足面试官要求的。
换一种思路:哈希。
如果能在O(1)的时间复杂度下,确定是否已经遍历过该字符,岂不快哉!而这正是哈希表的擅长的地方。
思路是这样的:
因为 ASCII 字符总数只有 256 个。所以辅助数组的长度只要常数级即可。
然后确定映射算法:此处采用了最简单的,直接将其减去 a 字符的值即可,这样为了能从辅助数组的 0 位置开始存储。
初始化辅助数组都为 0.然后如果哈希后的下标处的值不为 0 ,则说明已经遍历过了,将其拉黑,此处设立一个特殊字符 ‘#’。如果为 0 ,说明还没有存放字符,则存放之。
遍历完毕,辅助数组的第一个没有被拉黑的字符即为题目要求。
算法时间复杂度:O(n),空间复杂度为O(1)。
代码
package com.ans;
//空间复杂度为O(1),时间复杂度为O(n)
public class Solution3 {
public static char firstChar(String input) {
char[] arr = new char[256];
for(int k = 0 ; k < arr.length; k++) {
arr[k] = '0';
}
char[] ch = input.toCharArray();
char retChar = '$';
int index = 0;
for( int i = 0; i < ch.length ; i++) {
index = IndexFor(ch[i]);
System.out.println("Index is:" + index);
if(arr[index] == '0') {//如果该位置上没有字符,映射到相应的位置上
arr[index] = ch[i];
}
else {
arr[index] = '#';
}
}
for( int j = 0; j < arr.length; j++) {
if(arr[j] != '#') {
retChar = arr[j];
break;
}
}
return retChar;
}
public static int IndexFor(char c) {
if(!Character.isLetter(c)) {
System.out.println("输入不符合规范");
return -1;
}
return c - 'a';
}
public static void main(String[] args) {
String input = "abbaccddddeff";
char tmp;
if((tmp = firstChar(input)) != '$') {
System.out.println("第一个出现一次的字符是:" + tmp );
} else {
System.out.println("没有找到这样的字符");
}
}
}
总结
哈希。