[LeetCode] 467. Unique Substrings in Wraparound String 解题报告

来源:互联网 发布:fresh 知乎 编辑:程序博客网 时间:2024/06/05 20:24

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: 1Explanation: Only the substring "a" of string "a" is in the string s.

Example 2:

Input: "cac"Output: 2Explanation: There are two substrings "a", "c" of string "cac" in the string s.

Example 3:

Input: "zab"Output: 6Explanation: There are six substrings "z", "a", "b", "za", "ab", "zab" of string "zab" in the string s.

这一题才是名副其实的medium难度,感觉还需要动一下小脑筋,但是实现又不复杂。

首先,这一题需要明确两点:

  1. 尽管子串是无限长,但是事实上,子串的内容是已知的:也就是说从任意字符a-z开始,给定任意长度,都是它的子串。比如,从a开始,长度为3,abc是有效的子串;比如从x开始,长度为5,xyzab是有效的子串;
  2. 任何有效子串的子集任然是有效子串。比如,abcde是有效子串,那么它的子集abc,ab,cd......都是有效子串。
根据以上两点,于是我们在计算的时候,可以使用一个数组int[26]来存储找到的子串,如:int[1]=2,就代表当前我们已经找到了b开头,长度为2的子串,bc。另外,我们可以发现,事实上,对于一个字符开头的子串,它的最大长度,也就是以该字符开头的子串的数量,对于刚才那个例子,b开头的子串数量,就是2。因此,非常幸运,最后我们将整个数组求和,就可以得到总共找到的子串数量了。

接下来,在p中找到有效子串,也就比较简单了:
  1. 使用循环,从第一个字符开始遍历,只要后面的字符比当前的字符大1,就是有效子串,直到该子串结束,记录下该子串。
  2. 然后对子串中的子集进行处理,处理起来很简单,比如:当前子串是abcde,那么a开头长度为5,去找int[0],如果值小于5,就更新为5;b开头长度为4,找到int[1],如果小于4,就更新为4,以此类推。
  3. 然后继续遍历下一个有效子串,直到p结束。
代码如下,复杂度大约为O(N),实际时间大约大于2N:
public class Solution {public int findSubstringInWraproundString(String p) {if (p.length() == 0) {return 0;}int[] nArrDigits = new int[26];char[] cs = p.toCharArray();int nIndex = 0;int nStart = 0;int nEnd = 0;while (nIndex + 1 < cs.length) {if (cs[nIndex + 1] == ((((cs[nIndex] + 1) - 'a') % 26) + 'a')) {nEnd = nIndex + 1;} else {updateArray(nStart, nEnd, nArrDigits, cs);nStart = nIndex + 1;nEnd = nIndex + 1;}nIndex++;}// compute the last partupdateArray(nStart, nEnd, nArrDigits, cs);int nSum = 0;for (int i : nArrDigits) {nSum += i;}return nSum;}private void updateArray(int nStart, int nEnd, int[] nArrDigits, char[] cs) {for (int i = nStart; i <= nEnd; i++) {if (nArrDigits[cs[i] - 'a'] < nEnd - i + 1) {nArrDigits[cs[i] - 'a'] = nEnd - i + 1;}}}}

在上面的代码中,line10-11,可以看到nEnd和nIndex变量的值其实是一样的,只是为了逻辑清晰,用了两个变量。

0 0