找到第一个在字符串中出现1次的字符
最直观的想法就是遍历字符串,每遇到一个字符都遍历后面的字符,看有没有不重复的,这种做法最好是O(n),平均是O(n2),所以并不是最好的。
那第二种方法就是统计每个字符在字符串中出现的位置,那要有一个东西来记录就是用空间换时间,比如哈希表。
哈希表可以把一个字符映射成一个数字,所以哈希表的key定义为字符,value定义为数字,就可以遍历一遍得到每个字符的出现次数,然后再遍历一遍,出现一次的第一个字符就是第一个。hashmap可以直接拿来用,但这个题可以通过自己实现一个简单的哈希表。
哈希的原理就是把散列,将任意长度的输入压缩成一个固定长度的输出。性质是不同输入可能有相同输出,但每次输入后输出的结果要不变,若输入很多,则输出要均匀分布到输出域中。hashmap的实现就是将键经过hash之后得到一个固定长度的散列值,再模表的长度得到一个值,将键和值挂在这个值后面,如果有别的键也得到这个值,就挂在第一个值后面。
如果要自己实现一个哈希表,char有8位,所以共有种256可能,所以此时就以此时这个字符的ascii码作为key,其中存的值作为value表示键出现的个数。这个数组的大小为一个常数,所以空间复杂度可以算作O(1),总的时间复杂度为O(n)。
public class Solution {
public int FirstNotRepeatingChar(String str) {
int[] val=new int[256];
for(int i=0;i<str.length();i++){
val[str.charAt(i)]++;
}
for(int i=0;i<str.length();i++){
if(val[str.charAt(i)]==1)return i;
}
return -1;
}
}
如果此时不是要求字符而是汉字,那就不可以用一个256长度的数组了
因为汉字是两个字符,所以就是16位,弄一个2^16次的数组。6万多
也可以用标准的汉字编码,比如GBK,有21003个汉字编码,还不如直接用hashmap
定义函数,两个字符串为参数,要从第一个字符串中删除第二个字符串中出现的所有字符
所以这时就可以将第二个字符串存储到一个哈希表(简单)中,再遍历第一个字符串,如果发现有就删除。O(n)
定义函数,删除所有重复出现的字符
先遍历一遍,存到一个布尔型哈希表中,再遍历一遍,删除原有的字符,O(n)
判断字符串是否是变位词
变位词就是字母相同,出现次数也相同的字符串,这时就可以用一个哈希表遍历第一个,然后记录字母和出现次数,再遍历第二个,遇到就减去,如果哈希表值都是0则为变位词
找到字符流中第一次只出现一次的字符
是一个实时的,也就是随着字符的输入,这个值应该是不断变换的。
所以每输入一个字符就往哈希表中存一个值,如果这个值为-1,则是第一个存入,就把它变成此时这个值在字符中出现的位置,如果第二次出现就变成-2,这样的话,每个值都是记录的他出现的顺序,找到大于0且最小的值,就是该输出的字符。
记得初始化数组在构造函数中,不能在外面初始化。外面只能定义。
public class Solution {
//Insert one char from stringstream
static int[] arr=new int[256];
int num=-1;
public Solution(){
for(int i=0;i<256;i++){
arr[i]=-1;
}
}
public void Insert(char ch)
{
if(arr[ch]==-1){
arr[ch]=++num;
return;
}
if(arr[ch]!=-1 && arr[ch]>=0){
arr[ch]=-2;
}
}
//return the first appearence once char in current stringstream
public char FirstAppearingOnce()
{ int index=-1;
int seq=Integer.MAX_VALUE;
for(int j=0;j<256;j++){
if(arr[j]>=0 && arr[j]<seq){
seq=arr[j];
index=j;
}
}
if(seq!=Integer.MAX_VALUE){
return (char)index;
}else{
return '#';
}
}
}