class Solution { public int strStr(String haystack, String needle) { //进行异常判断 if (haystack==null||needle==null) return 0; for (int i = 0; i<haystack.length() - needle.length() + 1;i++){ int flag = 1; for (int j = i; j<i+needle.length(); j++){ if (haystack.charAt(j) != needle.charAt(j-i)){ flag = 0; break; } } if (flag == 1) return i; } return -1; } }
在字符串比较的时候,需要向上面的普通方法,一个一个字母去匹配比较。
在数字比较的时候,只需要比较数字的值即可。
那么,如何把字符串的比较变为数字的比较呢?----hashCode
可以通过字符,和一个数的乘积来转换为一个数字
比如abcd,拆分成a、b、c、d四个char类型,然后分别乘以对于的底数最后相加,就是这个字符串的Hash值。
有可能会超出整数的范围,那么可以对出来的值取模。
例: "abcde" = (a * 31^4 ) + (b * 31^3 ) + (c * 31^2 ) + (d * 31^1 ) + (e * 31^0 ) % 10^6 在此基础之上,如果要得到"bcde"的hash值怎么办? 模运算,用"abcde"的hash值 减去 (a * 31^4 )得到的值,再次模10^6即可
如果计算出来的hash值相同,那么可能两个字符串是相同的,还需要进一步判断。
如果计算出来的hash值不相同,那么两个字符串一定是不相同的。
效率取决于会有多少hash冲突。整个的时间复杂度是O(n + m)次,最后的匹配是m次。
class Solution { public int BASE = 1000000; public int strStr(String source, String target) { if (source == null || target == null){ return 0; } int m = target.length() if (m.length() == 0){ return 0; } // 31 ^ m int power = 1; for (int i = 0; i < m; i++){ power = (power * 31) % BASE; } //计算targetCode int targetCode = 0; for (int i = 0; i < m; i++){ targetCode = (targetCode * 31 + target.charAt(i)) % BASE; } int hashCode = 0; for (int i = 0; i < source.length(); i++){ //abc + d hashCode = (hashCode * 31 + source.charAt(i)) % BASE; //所计算的hashCode字符串长度小于目标的长度 if (i < m-1){ continue; } //abcd - a,所计算的hashCode字符串大于等于目标的长度,如i=2,m=2实际上已经计算了三个字符。 if (i >= m){ //减掉第一个字符后的hashCode,例如source.charAt(2 - 2) hashCode = hashCode - (source.charAt(i - m) * power)%BASE; if (hashCode < 0){//变为整数 hashCode += BASE; } } //double check the String if (hashCode == targetCode){ //注意此时的substring,在Java中是不包含最后一个的。边界处理的问题,左闭右开。 if (source.substring(i - m + 1, i + 1).equals(target)) { return i - m + 1; } } } return -1; } }