[Java]求字符串的交集

最近在做Android開發的時候遇到這樣一個問題。


服務器給客戶端推送應用的時候會發送一個apk的列表serviceApkList,其中有n個apk的包名(com.xxx),類似於這個樣子的。


因爲客戶端要到服務器端進行下載,然後可能出現下載失敗的情況(網絡不好,url錯誤等情況),本地也有一個apk的列表clientApkList


於是要在客戶端上做比較,serviceApkList與clientApkList中是否包含相同的包名。



那麼,問題來了。用什麼方法進行比較


既能實現目標,又能最大限度地優化時間複雜度呢?


最簡單的方法莫過於冒泡排序,一個個比,

可以實現,但時間複雜度爲o(n^2)


然後又想到優化冒泡排序,當比對相同時,刪除clientApkList中的相同包名

可以實現,但時間複雜度依然爲o(n^2/2)

在應用比較少的時候用這個方法可以,因爲是字符串,所以不能用什麼二分查找啊,歸併排序啊。


什麼,等等,在同學的提醒下,可以先對字符串進行歸併排序,然後使用二分查找的方法。

理論上來說,歸併排序的時間複雜度:O(n log 2n)+二分查找的時間複雜度:O(log n)

當應用比較多的時候用這個方法就可以大大減少時間複雜度了。


但是用什麼規則進行比較呢?


因爲Andoird apk的包名大多數以com開頭,所以比較開頭是沒有意義的,所以可以從結尾開始比較。

Java中是提供歸併排序的方法的,只要定義好比較的算法就可以了。

所以可以寫出如下的比較算法:

	private static class MyComparator implements Comparator<String> {

		@Override
		public int compare(String lhs, String rhs) {
			if (rhs == null) {
				throw new NullPointerException("the ComparableStr is null!");
			}
			if (lhs.equals(rhs)) {
				return 0;
			}
			int length = lhs.length() - 1;
			int anotherLength = rhs.length() - 1;
			// 比較
			int minLength = Math.min(length, anotherLength);
			for (int i = minLength - 1; i >= 0; i--) {
				int value = (int) (lhs.charAt(length--));
				int antherValue = (int) (rhs.charAt(anotherLength--));
				if (value != antherValue) {
					return value - antherValue;
				}
			}
			if (length != 0) {
				return lhs.charAt(length);
			} else if (anotherLength != 0) {
				return rhs.charAt(anotherLength);

			}
			return 0;
		}
	}


解釋一下,這裏是根據字符的ascii碼值比較的,char類型是可以直接轉換成int類型的,其值就是其ascii碼值,C語言中經常會用到這個東西。


然後就可以直接調用排序和比較方法了。

	public static void sort(List<String> list, MyComparator comparator) {
		Collections.sort(list, comparator);
	}

	public static boolean binaryFind(List<String> list, String target) {
		boolean result = Collections.binarySearch(list, target) > 0;
		return result;
	}


經過不大嚴密的單元測試,如下測試:

	List<String> list1 = new ArrayList<String>();
		String str1 = new String("abc");
		String str2 = new String("abc");
		String str3 = new String("bc");
		String str4 = new String("etyys");
		String str5 = new String("...");
		String str6 = new String("com.abv");
		String str7 = new String("com.abva");
		String str8 = new String("com.vvv");
		String str9 = new String("com.aav");
		list1.add(str1);
		list1.add(str2);
		list1.add(str3);
		list1.add(str4);
		list1.add(str5);
		list1.add(str6);
		list1.add(str7);
		list1.add(str8);
		list1.add(str9);
		sort(list1, new MyComparator());
		assertTrue(binaryFind(list1, "bc"));

結果:


通過!


總結:很多工作上的問題可以通過以前學過的知識解決,關鍵不是遇到足夠多的案例,而是遇到新問題的時候能不能通過知識的轉移來解決。

這可能是區別碼農跟攻城獅的標準之一。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章