Consider the string s to be the infinite wraparound string of "abcdefghijklmnopqrstuvwxyz", so s will look like this: "...zabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcd....". Now we have another string p. Your job is to find out how many unique non-empty substrings of p are present in s. In particular, your input is the string p and you need to output the number of different non-empty substrings of p in the string s. Note: p consists of only lowercase English letters and the size of p might be over 10000. Example 1: Input: "a" Output: 1 Explanation: Only the substring "a" of string "a" is in the string s. Example 2: Input: "cac" Output: 2 Explanation: There are two substrings "a", "c" of string "cac" in the string s. Example 3: Input: "zab" Output: 6 Explanation: There are six substrings "z", "a", "b", "za", "ab", "zab" of string "zab" in the string s.
这道题我一开始发现了数学规律:
length of consecutive chars vs number of different substring
“a” -> 1 = 1
"ab" -> 3 = 1+2
"abc" -> 6 = 1+2+3
"abcd" -> 10 = 1+2+3+4
于是打算计算string p里面每一段consecutive substring的length是多少,比如abcxyz, 两段分别为“abc”“xyz”, len分别为3和3,#of substring分别是6和6,总数是6+6。 但是这个方法没法处理有重复的,比如abczab,"abc"依然能产生6个substring, 然而"zab"就有重复了,只能产生3个different substring.
如何处理重复呢? “abc”和“zab”里面的"ab"要同时考虑到,于是就有了DP的想法:
total number of different substring = sum of {number of different substring end by each char}
Further,
number of different substring end by each char = length of longest contiguous substring ends with that letter.
Example "abcd"
, the number of unique substring ends with 'd'
is 4, apparently they are "abcd", "bcd", "cd" and "d"
.
If there are overlapping, we only need to consider the longest one because it covers all the possible substrings. Example:"abcdbcd"
, the max number of unique substring ends with 'd'
is 4 and all substrings formed by the 2nd "bcd"
part are covered in the 4 substrings already.
1 public class Solution { 2 public int findSubstringInWraproundString(String p) { 3 if (p==null || p.length()==0) return 0; 4 int[] nums = new int[26]; //numbers of different substrings end with a specific char 5 6 int longestConsec = 0; 7 for (int i=0; i<p.length(); i++) { 8 if (i>0 && (p.charAt(i-1)+1 == p.charAt(i) || p.charAt(i-1)-25 == p.charAt(i))) { 9 longestConsec++; 10 } 11 else longestConsec = 1; 12 13 char c = p.charAt(i); 14 nums[(int)(c-'a')] = Math.max(nums[(int)(c-'a')], longestConsec); 15 } 16 17 int res = 0; 18 for (int num : nums) { 19 res += num; 20 } 21 return res; 22 } 23 }