题目描述
在一个字符串(0<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置, 如果没有则返回 -1(需要区分大小写).


这个题目既然是找是否出现,并且由于每个字符需要返回第一次出现,因此需要记录次数,可以使用数组来完成出现次数的统计,而数组可以改进成TreeSet,因为实现了排序,或者是使用Map集合来统计次数。

写法1:

利用数组统计次数,这里可以建一个二维数组,但是,考虑到ASCII码中,字符对应某个数字,所以可以将字符对应的数字当做数组的角标,因此,可以只用一个一维数组即可。(也就是说,当你写一个arr[a],是会被认成arr[97],而Map不行)
注意:ASCII码一共是127个数,而小写z对应的是122,因此数组可以设置的最小角标数为122,所以最小必须创建一个123的数组,也可以128,这样所有的字符都能统计(PS:有人用256我是没想到为什么,大家知道的可以告诉我)。
  当然,也可以使用偏移量,毕竟A-Z对应的ASCII码为65-90,a-z对应的ASCII码值为97-122,用65到122这58个数也可以代替,所以使用偏移量需要做减法,然后创建大小58的数组即可。甚至可以用两次偏移,这样就只用大小52的数组了。但是为了少死一点脑细胞(我不想换算),我使用的是123个。不死脑细胞还占用空间较小的做法。
  字符对应的数字,将该数字作为索引,该索引处的元素用来统计出现的次数,遍历完后,再进行一次遍历,找到次数只为1的,并返回该数组中索引所表示的字符。就是这么个逻辑。

public class Solution {
    public int FirstNotRepeatingChar(String str) {
        if(str==null || str.length() == 0)
            return -1;
        int[] count = new int[123];
        //类似hash的方法来存储字符出现的次数
        for(int i=0; i < str.length();i++)
            count[str.charAt(i)]++;//进行统计
        //添加完字符后,再访问一遍数组,可以找到某个只出现一次的字符
        for(int i=0; i < str.length();i++){
            if(count[str.charAt(i)]==1)
                return i;
//这里不能遍历count数组,因为遍历count数组只能返回出现1次的字符,或者是某个字符出现的次数
//只有再拿着原字符串数组的角标遍历,才能将角标和出现次数对应上
        }
        return -1;
    }
}
//这个方法也可以改写成Set。只不过需要保证是有序的Set。

写法2:

使用Map集合来做,逻辑大致相同,只是添加的时候改动比较大。添加时,需要和Map的key比较,然后对Value进行维护。

import java.util.HashMap;
public class Solution {
    public int FirstNotRepeatingChar(String str) {
          if(str.length() == 0|| str == null){
            return -1;
        }
        HashMap<Character,Integer> map = new HashMap<>();
        for(int i = 0; i < str.length();i++){
//Map的逻辑是,如果Map不包含这个key,那就添加,注意添加的是字符,和出现的次数(添加时默认是1)
            if(!map.keySet().contains(str.charAt(i))){
                map.put(str.charAt(i),1);
            }else{//包含,则计数+1.map.get(str.charAt(i))就是拿到这个具体的次数即value
                map.put(str.charAt(i),map.get(str.charAt(i))+1);
            }
        }
        for(int i = 0; i < str.length();i++){//老规矩,只能对原字符串再次遍历
            if(map.get(str.charAt(i)) == 1){
                return i;
            }
        }
        return -1;//没找到就返回-1
    }
}
//keySet()  返回一个 SetMap视图中包含的键。