問題:給定兩個字串s1和s2,要求判定s2是否能夠通過s1做迴圈移位得到字串包含,例如s1=AABCD,s2=CDAA,則返回true,如果s1=ABCD,s2=ACBD,則返回false。
解法1:對字串做迴圈移位,然後判斷移位後的字串是否包含s2.這種方法需要窮舉,效率較低。
public static boolean containStr1(String s1,String s2){char[] str1=s1.toCharArray();char[] str2=s2.toCharArray();for(int i=0;i<str1.length;i++){char temp=str1[0];for(int j=0;j<str1.length-1;j++){str1[j]=str1[j+1];}str1[str1.length-1]=temp;if(charArrayContain(str1,str2)){return true;}}return false;}
上面用到了一個判斷兩個字元數組是否包含的函數,如下定義:
private static boolean charArrayContain(char[] s1,char[] s2){if(s1==null||s2==null)return false;if(s1.length==0||s2.length==0)return false;if(s1.length>=s2.length){int i=0,j=0;while(i<s1.length&&s1[i]!=s2[j]){i++;}for(;i<s1.length&&j<s2.length;i++,j++){if(s1[i]!=s2[j])break;}if(j==s2.length)return true;}return false;}
除了上面的方法,還有更好的方法嗎?下面介紹方法2
解法2:我們知道如果字串s2可以通過s1移位後的字串包含,那麼字串s2肯定在s1s1組合字元串中。下面我們使用JAVA內建的函數來寫代碼。
public static boolean containStr2(String s1,String s2){s1=s1.concat(s1);return s1.contains(s2);}
是不是覺得很簡潔,而且從運行結果來看,這個演算法比解法1要快,需要注意的是這個方法是通過增加空間複雜度來較低時間的複雜度的。有人會想,Java內建的函數難道都很快能達到我們的要求嗎?我也不確定,不過我們嘗試自己寫函數來實現解法2中的函數。如解法3所示:
解法3:該方法使用與解法2一樣的思想,不同的是我們自己編寫實現代碼。
public static boolean containStr3(String s1,String s2){char[] str1=new char[s1.length()+s1.length()];for(int i=0;i<s1.length();i++){str1[i]=s1.charAt(i);str1[i+s1.length()]=s1.charAt(i);}char[] str2=s2.toCharArray();return charArrayContain(str1,str2);}
通過運行我們比較了一下兩種速度,基本上還是差不多的呵呵。
那麼除了上面的方法外,還有其它方法嗎?還有更快的方法嗎?接下來我們將另一種方法。
解法4:要想判斷s1移位後的字串是否包含s2,其實意思就是“如果我們把字串看成是一個迴圈字串,那麼問s2字串中的字元能否在s1這個迴圈字串中順序連續的出現,如果能,則說明包含,如果不能,則說明不包含!”。下面我們根據這個思路編寫實現代碼。如下所示:
public static boolean containStr4(String s1,String s2){int i=0,j=0;while(i<s1.length()&&s1.charAt(i)!=s2.charAt(j))i++;for(;i<s1.length()&&j<s2.length();){if(s1.charAt(i)!=s2.charAt(j))return false;i=(i+1)%s1.length();j++;}if(j==s2.length())return true;return false;}
上面我們已經講了好幾種演算法,下面給出這幾種演算法的運行結果:
true用時:199355納秒true用時:49899納秒true用時:43268納秒true用時:35764納秒
從運行結果就可以看出,解法4用時最少,是最快的演算法,解法3和解法2基本差不多,解法1速度最慢。
歡迎討論,轉載請註明出處!