問題描述:
假設這有一個各種字母組成的字串,假設這還有另外一個字串,而且這個字串裡的字母數相對少一些。從演算法是講,什麼方法能最快的查出所有小字串裡的字母在大字串裡都有? 比如,如果是下面兩個字串: String 1: ABCDEFGHLMNOPQRS String 2: DCGSRQPOM 答案是 true,所有在 string2 裡的字母 string1 也都有。 如果是下面兩個字串:
String 1: ABCDEFGHLMNOPQRS String 2: DCGSRQPOZ
答案是 false,因為第二個字串裡的 Z 字母不在第一個字串裡。
相關問題:字串中第一個值出現一次的字元。
方法1:hash
把字串1中的每個字元都映射到數組中,數組的下標是char強制類型轉換為int之後的
值大小,給定下標的數組元素的值為該字元在字串中出現的次數。再拿字串2中的字元一一
對比即可。時間複雜度是O(m+n),空間複雜度是O(1) (固定是256);
很像計數排序,因為此時hash的演算法是 hash(c)=(int)c。
代碼如下:
public class ContainChar {public char[] c1;public char[] c2;public int[] h = new int[256];public ContainChar(String s1,String s2){this.c1 = s1.toCharArray();this.c2 = s2.toCharArray();}public int hash(char c){return (int)c;}public boolean isContain(){for(int i = 0; i < c1.length; i++){h[hash(c1[i])]++;}for(int i = 0; i < c2.length ;i++){if(hash(c2[i]) == 0){return false;}}return true;}public static void main(String[] args){String s1 = "abcdefghijk";String s2 = "dhk";ContainChar c = new ContainChar(s1, s2);System.out.println(c.isContain());}}
輸出為ture。
如果問題是第一個只出現一次的字元,將字串映射之後,在一次遍曆字串,找到只出現一次的字元返回即可。
類似的,找到只出現2次,3此等等都可以照這個思路。
字串是最適合用計數排序的,因為字元的最大值很小(256,雖然char是2byte,但是ascii碼都位於前256)。
方法2:BitMap
BitMap常常用於輸入規模很大,給你40億個輸入,再給你一條記錄問你是否在輸入中,這時候用BitMap或者布隆過濾器
都是適合的。原理:一個byte 0 是 00000000 ,輸入一個4 ,變為 00001000。再輸入一個7,變為 00001001。意思是
用一個byte就能表示0~7的數。簡單例子:
public class BitMap {public byte[] b;//輸入數組和數組最大值public BitMap(int[] a,int max){b = new byte[(max % 8) +1];for(int i = 0;i < a.length; i++){add(a[i]);}}//把給定的value放到Bitmap中public void add(int value){int k = value / 8; //找到該value的在數組中位置int mod = value % 8; //找到應該將那一位置1byte num = 1;b[k] = (byte) (b[k] | (num<<(7-mod)));}public boolean isContain(int value){//判斷給定數是否在bitmap中int k = value / 8; //找到該value的在數組中位置int mod = value % 8; //找到應該將那一位置1byte num = 1;if((b[k] & (num<<(7-mod))) == 0){return false;}elsereturn true;}public static void main(String[] args){//用2byte的大小表示了10個int(40byte)int[] a = {1,2,3,4,5,6,7,8,9,10};BitMap b = new BitMap(a, 10);System.out.println(b.isContain(8) + " " + b.isContain(11));}}
輸出為 true false
類似的,把第一個字串載入到bitmap中之後,再依次對比即可。
(似乎這個用bitmap有點複雜。。。不過還是能解決問題)
對於第一個只出現一次的字元,就更加複雜了,我們用2位來表示一個數,00 00 00 01 代表4出現了1次,00 00 00 10 代表4出現了至少2次……。
方法3:找到256個素數,和字元一一對應。將字串1乘起來。依次看字串1的積能不能將所有字串2的字元對應的素數整除。
很神奇的做法!