【图解演算法】【Hash】 LeetCode 459 Repeated Substring Pattern

Question link: https://leetcode.com/problems/repeated-substring-pattern/

class Solution {        long magic_num = 31;     long mod_num = 1000000000 + 7;        public boolean repeatedSubstringPattern(String s) {        // only lowercase         // for - pick one substring        //  for - repeat and check         if (s.isEmpty()) return false;                        // get target hash         long target_hash = hash(s);                // initailization        Long now_hash = null;        int i = 0;                int str_size = s.length();        while (true) {            if (i >= str_size) break;             int substring_size = i + 1;                        // calculate hash             if (now_hash == null) {                now_hash = hash(s.substring(0, 1));                now_hash = mod(now_hash, mod_num);            }else {                // ab -> ab_ move left                 now_hash *= magic_num;                 now_hash = mod(now_hash, mod_num);                // ab_ + c                now_hash += s.charAt(i);                now_hash = mod(now_hash, mod_num);            }            System.out.println("i: " + i);            if (str_size % substring_size != 0 // must be a factor               || str_size == substring_size) // must append at least once             {                i++;                continue;            }                        // assemble as a whole string for compare            int chunk_num = str_size/substring_size;            long now_assembled_hash = now_hash;            for (int k = 1; k < chunk_num; k++) { // start from k = 1                // abc -> abc___ move left                for (int m = 0; m < substring_size; m++) {                    now_assembled_hash *= magic_num;                    now_assembled_hash = mod(now_assembled_hash, mod_num); // be very careful about overflow                 }                // abc___ + abc -> abcabc                now_assembled_hash = mod(now_assembled_hash, mod_num);                now_assembled_hash += now_hash;                now_assembled_hash = mod(now_assembled_hash, mod_num);            }            // check hash (belive in god, believe in your hash function)            System.out.println(chunk_num + "-" + now_assembled_hash + ":" + target_hash);            if (now_assembled_hash == target_hash) {                return true;            }                        i++;        }                return false;            }            private long hash(String s) {        long result = 0;                for (int i = 0; i < s.length(); i++) {            result *= magic_num;            result = mod(result, mod_num);            result += s.charAt(i);            result = mod(result, mod_num);        }                return result;            }        private long mod(long num, long mod){        return (num % mod + mod) % mod;       }        }

pick substring and calculate rolloing hash:
hash_val = 0
"a" = hash_val * magic_num + "a"
"ab" = hash_val * magic_num + "b"
"abc" = hash_val * magic_num + "c"
...

check if current substring is a factor of original string length
if (str_size % substring_size != 0)

assemble current substring hash into a whole-string hash

compare hash value
if (now_assembled_hash == target_hash) {
return true;
}

In the implementation, we leverage hash to avoid compare each substring one by one.
As a result, our time complexity is:

n * (chunk_num * (substring_size))

furthermore, when substring_size goes up, chunk_num goes down.
Therefore, roughly speaking, our time complexity will lean toward to original string length

n * str_size

At least, this is my thought. Let's discuss!

note: in this implementation, please be very careful about overflow while calculating hash value. really an evil in the detail.


关于作者: 网站小编

码农网专注IT技术教程资源分享平台,学习资源下载网站,58码农网包含计算机技术、网站程序源码下载、编程技术论坛、互联网资源下载等产品服务,提供原创、优质、完整内容的专业码农交流分享平台。

热门文章