字符串Hash + 二分
题目描述:
你需要从空字符串开始 构造 一个长度为 n 的字符串 s ,构造的过程为每次给当前字符串 前面 添加 一个 字符。构造过程中得到的所有字符串编号为 1 到 n ,其中长度为 i 的字符串编号为 si 。
比方说,s = "abaca" ,s1 == "a" ,s2 == "ca" ,s3 == "aca" 依次类推。
si 的 得分 为 si 和 sn 的 最长公共前缀 的长度(注意 s == sn )。
给你最终的字符串 s ,请你返回每一个 si 的 得分之和 。
Java代码:
1 class Solution { 2 3 int N = 100000 + 10; 4 5 int P = 13131; 6 7 long[] h = new long[N]; 8 9 long[] p = new long[N]; 10 11 public void setHAndP(char[] c, int n) { 12 p[0] = 1; 13 for (int i = 1; i <= n; i++) { 14 h[i] = h[i - 1] * P + (int)c[i - 1]; 15 p[i] = p[i - 1] * P; 16 } 17 } 18 19 public long sumScores(String s) { 20 char[] c = s.toCharArray(); 21 int n = c.length; 22 setHAndP(c, n); 23 long res = 0; 24 for (int i = n; i >= 2; i--) { 25 int left = i; 26 int right = n; 27 while (left <= right) { 28 int mid = (left + right) / 2; 29 int len = mid - i + 1; 30 int s1 = 1; 31 int e1 = s1 + len - 1; 32 int s2 = i; 33 int e2 = mid; 34 // 二分 35 if (check(s1, e1, s2, e2)) { 36 left = mid + 1; 37 } else { 38 right = mid - 1; 39 } 40 } 41 res += (right - i + 1); 42 } 43 return res + n; 44 } 45 46 // abcde 47 public boolean check(int s1, int e1, int s2, int e2) { 48 long r1 = h[e1] - (h[s1 - 1] * p[e1 - s1 + 1]); 49 long r2 = h[e2] - (h[s2 - 1] * p[e2 - s2 + 1]); 50 return r1 == r2; 51 } 52 }
力扣链接:
https://leetcode-cn.com/problems/sum-of-scores-of-built-strings/