Java演算法面試題(004) 實現一個演算法來確定一個字串是否具有所有唯一的字元

劉近光發表於2017-11-29

問題分析

你應該首先詢問面試官,需要處理的字串是一個ASCII字串還是一個Unicode字串。提出這個問題將展現你對細節的考慮和你堅實的電腦科學基礎。為了簡單起見,我們將假設字串為ASCII型別。
一種解決方案是建立一個布林值陣列,其中位於索引i的標誌指示字元i是否包含在字串中。你第二次看到這個標識,你可以立即返回false。如果字串長度超過了唯一字元的數量,我們也可以立即返回false。

演算法

具體的演算法實現如下:

	public boolean isUniqueChars(String str) {
		if (str.length() > 128) {
			return false;
		}

		boolean[] charSet = new boolean[128];

		for (int i = 0; i < str.length(); i++) {
			int val = str.charAt(i);
			if (charSet[val]) { // already found this char in string
				return false;
			}

			charSet[val] = true;
		}

		return true;
	}
這個程式碼的時間複雜度是O(n),其中n是字串的長度。
我們可以通過使用位向量來將我們的空間使用減少八倍。我們將假設,在下面的程式碼中,該字串只使用小寫字母a到z。
	/*
	 * We can reduce our space usage by a factor of eight by using a bit vector.
	 * We will assume, in the below code, that the string only uses the
	 * lowercase letters a through z. This will allow us to use just a single
	 * int.
	 */
	public boolean isUniqueChars(String str) {
		int checker = 0;
		for (int i = 0; i < str.length(); i++) {
			int val = str.charAt(i) - 'a';

			if ((checker & (1 << val)) > 0) {
				return false;
			}

			checker |= (1 << val);
		}
		return true;
	}

進一步的問題

上面的演算法,個人認為都是比較典型的以空間換時間的思路。如果我們不能使用額外的資料結構,可以考慮下面的演算法實現:
1. 將字串的每個字元與字串的每個其他字元進行比較。這將花費O(n2)時間和O(1)空間。
2. 如果允許修改輸入字串,我們可以在O(n log(n))時間內對字串進行排序,然後再檢查相鄰字串是否相同。

演算法擴充

接下來,我們來擴充一下本文中使用的演算法,來檢查兩個字串是否具有相同的字元數(permutation)。我們也可以使用排列的定義 - 具有相同字元數的兩個詞來實現這個演算法。我們只是迭代這個程式碼,計算每個字元出現的次數。之後,我們比較兩個陣列。

	public boolean permutation(String s, String t) {
		if (s.length() != t.length()) {
			return false;
		}

		int[] letters = new int[128];

		char[] s_array = s.toCharArray();
		for (char c : s_array) {
			letters[c]++;
		}

		for (int i = 0; i < t.length(); i++) {
			int c = (int) toString().charAt(i);
			letters[c]--;
			
			if (letters[c] < 0) {
				return false;
			}
		}
		
		return true;
	}

相關文章