leetcode-387-字符串中的第一个唯一字符(first unique character in a string)-java

题目及用例

package pid387;
/* 字符串中的第一个唯一字符

给定一个字符串,找到它的第一个不重复的字符,并返回它的索引。如果不存在,则返回 -1。

案例:

s = "leetcode"
返回 0.

s = "loveleetcode",
返回 2.



*/


public class main {
	
	public static void main(String[] args) {
		String [] testTable = {"leetcode","A man, a plan, a canal: Panama","loveleetcode"};
		for (String ito : testTable) {
			test(ito);
		}
	}
		 
	private static void test(String ito) {
		Solution solution = new Solution();
		int rtn;
		long begin = System.currentTimeMillis();
		System.out.print(ito);		    
		System.out.println();
		//开始时打印数组
		
		rtn= solution.firstUniqChar(ito);//执行程序
		long end = System.currentTimeMillis();	
		
		System.out.println(":rtn" );
		System.out.print(rtn);
		System.out.println();
		System.out.println("耗时:" + (end - begin) + "ms");
		System.out.println("-------------------");
	}

}

解法一(成功,54ms,速度一般)
使用hashmap,以character为key,index为value,一旦出现重复key,设value为-1
最后遍历hashmap,设min为length,如果value不为1,且比min小,则min=value
最后如果min还等于length,则说明全部重复,设min=-1

package pid387;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map.Entry;

public class Solution {
public int firstUniqChar(String s) {
    int length=s.length();
    if(length==0){
    	return -1;
    }
    if(length==1){
    	return 0;
    }
    HashMap<Character, Integer> map=new HashMap<>();
    for(int i=0;i<length;i++){
    	Character now=s.charAt(i);
    	if(!map.containsKey(now)){
    		map.put(now, i);
    	}
    	else{
    		map.put(now, -1);
    	}
    }
    
    int min=length;
    for(Character key: map.keySet()){
    	int now=map.get(key);
    	if(now!=-1){
    		if(now<min){
    			min=now;
    		}
    	}
    }
    if(min==length){
    	min=-1;
    }
        
	return min;
    }

}

解法二(别人的)
用linkedhashmap可以最后不用循环找第一个,直接找到

用一个LinkedHashMap实现,key为字母,value如果第一次插入存入索引,再次插入存-1,然后遍历HashMap,找到第一个不是-1的value(LinkedHashMap保证了插入顺序,所以找到的一定是第一个唯一字
解答:

class Solution {
    public int firstUniqChar(String s) {
        Map<Character, Integer> sCount = new LinkedHashMap<Character, Integer>();
        for (int i = 0; i < s.length(); i++) {
            char letter = s.charAt(i);
            if (sCount.containsKey(letter)) {
                sCount.put(letter, -1);
            }
            else {
                sCount.put(letter, i);
            }
        }
        Iterator iter = sCount.entrySet().iterator();
        while (iter.hasNext()) {
            Map.Entry<Character, Integer> entry = (Map.Entry)iter.next();
            if (entry.getValue() == -1) {
                continue;
            }
            return entry.getValue();
        }
        return -1;
    }
}

解法三(成功,20ms,较快)
这个题目,由于这里只有小写字母且ASCII码是连续的,于是可以把数组当作hash表用,0为初始值,正数为普通index+1,如果有多个则为integer.max
先遍历一遍字符串,在遍历一遍数组,找到有一个而且是最初的index

	public int firstUniqChar(String s) {
		//里面每格对应一个小写字母,0对应a,25对应z
		//里面的值为对应字母的位置+1,0为初始值,正数为普通index+1,如果有多个则为integer。max
		int[] index=new int[26];
		for(int i=0;i<s.length();i++){
			int nowIndex=index[s.charAt(i)-'a'];
			if(nowIndex==0){
				//这说明之前没有过这个字母
				index[s.charAt(i)-'a']=i+1;
				continue;
			}
			//如果不为0,则说明之前已经有过了,直接变成max
			index[s.charAt(i)-'a']=Integer.MAX_VALUE;
		}
		int result=Integer.MAX_VALUE;
		for(int i=0;i<26;i++){
			if(index[i]>0&&index[i]<Integer.MAX_VALUE){
				//这说明有这个字母,而且只出现一次
				//找到最小的下标
				if(result>index[i]){
					result=index[i];
				}
			}
		}
		if(result==Integer.MAX_VALUE){
			//这说明都重复了
			return -1;
		}
		else{
			//result存储的是index+1
			return result-1;
		}		
    }

解法4(别人的)
算法的思路就是遍历一遍字符串,然后把字符串中每个字符出现的次数保存在一个散列表中。这个过程的时间复杂度为 O(N),其中 N 为字符串的长度。

接下来需要再遍历一次字符串,这一次利用散列表来检查遍历的每个字符是不是唯一的。如果当前字符唯一,直接返回当前下标就可以了。第二次遍历的时间复杂度也是 O(N)。

class Solution {
    public int firstUniqChar(String s) {
        HashMap<Character, Integer> count = new HashMap<Character, Integer>();
        int n = s.length();
        // build hash map : character and how often it appears
        for (int i = 0; i < n; i++) {
            char c = s.charAt(i);
            count.put(c, count.getOrDefault(c, 0) + 1);
        }
        
        // find the index
        for (int i = 0; i < n; i++) {
            if (count.get(s.charAt(i)) == 1) 
                return i;
        }
        return -1;
    }
}

复杂度分析

时间复杂度: O(N)只遍历了两遍字符串,同时散列表中查找操作是常数时间复杂度的。

空间复杂度: O(N) 用到了散列表来存储字符串中每个元素出现的次数。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值