467. 环绕字符串中唯一的子字符串

138 阅读2分钟

467. 环绕字符串中唯一的子字符串

题目

把字符串 s 看作是 “abcdefghijklmnopqrstuvwxyz” 的无限环绕字符串,所以 s 看起来是这样的: "...zabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcd...." . 现在给定另一个字符串 p 。返回 s 中 唯一 的 p 的 非空子串 的数量 。 

分析

  • 分析到数据范围1e5,求非空子串的数量,算法的时间复杂度只能为O(n)、O(nlogn)、O(n根号2)
  • 看题解算法使用到了动态规划,下面来分析题目如何使用动态规划,也就是动态规划五部曲
  • 确定dp[i]含义,dp[i]表示以p[i]结尾的最大有效子串(子串相邻连续)的长度
    • 当不考虑子串重复问题时,若 dp[i]=k,则以 s[i] 为结尾的有效子串数量为 k 个(对应以 s[i]为结尾,长度范围为 [1, k]的子数组)。
    • 举个例子 p = "zab" , 那么以b结尾的有效子串数量为3个,其中包含:b、ab、zab。 那么以a结尾的有效子串数量为2个,其中包含:a、za。 那么以z结尾的有效子串数量为1个,其中包含:z。
  • 状态转移方程
    • 存在s[i-1]并且是[i]能够接在s[i-1]后面,则有dp[i] = dp[i-1] + 1;
    • 不存在s[i-1]或者s[i]不能接在s[i-1]后面,则dp[i] = 1,含义为 s[i]s[i] 只能自身组成子串
  • 循环每次比较出s[i]结尾的最大有效子串(子串相邻连续)的长度即可,记录在status[s[i] - 'a']中
  • 统计status[]数组的值即可
    public int findSubstringInWraproundString(String p) {
        int n = p.length();
        int[] dp = new int[n];
        int[] status = new int[26];
        int prev = 0;
        for (int i = 0; i < n; i++) {
            int cur = p.charAt(i) - 'a';
            if (i > 0 && (prev + 1) % 26 == cur) {
                dp[i] = dp[i-1] + 1;
            } else {
                dp[i] = 1;
            }
            status[cur] = Math.max(status[cur],dp[i]);
            prev = cur;
        }
        return Arrays.stream(status).sum();
    }
}