找到字符串中第一個不重復的元素


題目:在一個字符串中找到第一個沒有重復元素的字符並返回。

例:輸入:"yellow"   

  返回:“y”

  輸入:"tooth"

  返回:“h”

  輸入:“coco”

  返回:“”

這個題目我在亞馬遜電話面試中遇見過,后來再一家日本公司面試中也遇見過。盡管這個問題並沒有涉及到比較高級的編程思想,比如動態編程dynamic Programming或者Divide and Conquer,但是如果對數據結構或者算法並不很熟練的人來說,還是會構成一定的困難。

好了,那么現在就來分析一下這個問題。

首先,最直觀的解法就是利用循環挨個兒從第一個元素起往后面找有沒有重復,如果遍歷完成后還沒有,那么這個元素就是第一個沒有重復的元素,直接在循環體中返回值就可以了。那么具體解法就需要兩個循環控制,第一個用來定位要查看的元素,第二個循環用來在字符串中找有沒有跟他重復的元素。這個算法的時間復雜度是O(n2), 因為假設這個字符串中元素都有重復,那么第一個循環需要遍歷n次,第二個循環也需要遍歷n次。空間復雜度是O(c),為常數,因為我們並沒有添加新的數據結構。Java代碼如下:

public static String findCharInPlace(String s){
		int len = s.length();
		if(len <= 0) return null;
		boolean repeated = false;
		for(int i=0;i<s.length();i++){
			repeated = false;
			int j=0;
			for(;j<s.length();j++){
				if(j!=i&&s.charAt(j)==s.charAt(i)){
					repeated = true;
					break;
				}
			}
			if(!repeated)
				return s.charAt(i)+"";
		}
		
		return  "";
	}

  那么現在我們來看看有沒有第二種解法。我們注意到,在Java中的Map類。我們可以用HashMap映射這個字符串的元素作為key,讓每一個元素對應一個重復出現次數的標記,這個標記我們用一個Integer。HashMap<Character, Integer>.我們從頭遍歷這個字符串,如果后面重復出現了之前出現過的元素,我們就相應這個元素對應的重復出現標記加一。最后在遍歷這個Map,找到第一個重復出現標記為一的元素並返回。可這里問題不僅要找到沒有重復元素的元素,還要是返回第一個不重復的。但是HashMap的一個問題就是它是無序的。EntrySet並不會按照插入次序來排列,所以怎么辦呢。我們知道Java中LinkedList是有序的。所以這里我們就可以用到LinkedHashMap來實現這個功能。 LinkedHashMap結合了LinkedList和HashMap的優點,得到的EntrySet是由一個內部的LinkedList來維護的。所以我們就可以用這個神奇的類來實現這個解法。代碼如下:

	public static String findChar(String s) {
		String ans = null;
		Map<Character, Integer> sMap = new LinkedHashMap<Character, Integer>();
		for(char c: s.toCharArray()){
			if(!sMap.containsKey(c)){
				sMap.put(c, 1);
			}else{
				sMap.put(c, sMap.get(c)+1);
			}
		}
		for(Entry<Character, Integer> en: sMap.entrySet()){
			if(en.getValue()==1) return en.getKey().toString();
		}
		return ans;
	}

  現在我們來分析一下這個算法的復雜度。LinkedHashMap中add,contail和remove並沒有因為有了LinkedList這個特性而增加復雜度,依然是常數級別的復雜度。所以第一個遍歷標記的時間復雜度是O(n),第二遍遍歷查找的時間復雜度也是O(n),所以整個算法的時間復雜度是O(n).因為我們新添加了LinkedHashMap來對每個字符進行標記,所以空間復雜度是O(n).但從時間上來講,還是相當快的。

  那么我們來分析一下,還有沒有更好的實現方法,比如達到O(log(n))的。沒有。為什么呢?因為為了判斷是否有元素重復,在最壞情況下(比如所有元素都是重復的)我們至少要完全遍歷這個字符串一遍才能確定,復雜度為O(n),所以,這個問題的最優解是O(n).

  最后讓我們來分析對比一下這兩個方法的優劣。表面上,單從時間復雜度上來說,算法2無疑是最優的。但是算法2有個問題,是新添加了數據結構LinkedHashMap,所以空間復雜度要高於算法1,這在輸入字符串長度不是很大,並且重復度不高,而同時對系統內存資源比較緊俏的情況下來說,算法1有時會比算法2要好一些。因此,在評判一個算法優劣的時候,要結合應用場景來看,而不能單純從時間復雜度或者空間復雜度上來看。

 

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM