哈希集合或动态规划:求解《467. 环绕字符串中唯一的子字符串》

2022-05-25 13:24:51
哈希集合或动态规划,求解《467. 环绕字符串中唯一的子字符串》

例题

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

把字符串 s 看作是 “abcdefghijklmnopqrstuvwxyz” 的无限环绕字符串,所以 s 看起来是这样的:
"...zabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcd...." .
现在给定另一个字符串 p 。返回 s 中 唯一 的 p 的 非空子串 的数量 。
示例 1:
输入: p = "a"
输出: 1
解释: 字符串 s 中只有一个"a"子字符。

答案

哈希集合 · 同构数组实现

var findSubstringInWraproundString = function(p) {
  const n = p.length, visited = new Uint8Array(26 * 10 ** 5 - 1)
  let r = 0
  for (let i = 0; i < n; i++) {
    const start = (p.charCodeAt(i) - 97) * 10 ** 5
    let l = 0
    if (visited[start + l] === 0) r++
    visited[start + l] = 1
    for (let j = i + 1; j < n; j++) {
      l++
      const diff = p.charCodeAt(j) - p.charCodeAt(j - 1)
      if (diff !== 1 && diff !== -25) break
      if (visited[start + l] === 0) r++
      visited[start + l] = 1
    }
  }
  return r
};
function findSubstringInWraproundString(p: string): number {
  const n = p.length, visited = new Uint8Array(26 * 10 ** 5 - 1)
  let r = 0
  for (let i = 0; i < n; i++) {
    const start = (p.charCodeAt(i) - 97) * 10 ** 5
    let l = 0
    if (visited[start + l] === 0) r++
    visited[start + l] = 1
    for (let j = i + 1; j < n; j++) {
      l++
      if ((p.charCodeAt(j) - p.charCodeAt(j - 1) + 26) % 26 !== 1) break 
      if (visited[start + l] === 0) r++
      visited[start + l] = 1
    }
  }
  return r
};

动态规划

var findSubstringInWraproundString = function(p) {
  const n = p.length, dp = new Uint32Array(26)
  dp[p.charCodeAt(0) - 97] = 1
  for (let i = 1, l = 1; i < n; i++) { 
    dp[p.charCodeAt(i) - 97] = Math.max(dp[p.charCodeAt(i) - 97], (p.charCodeAt(i) - p.charCodeAt(i - 1) + 26) % 26 === 1 ? ++l : l = 1)
  }
  let sum = 0
  for (let i = 0; i < 26; i++) sum += dp[i]
  return sum
};
function findSubstringInWraproundString(p: string): number {
  const n = p.length, dp = new Uint16Array(26)
  dp[p.charCodeAt(0) - 97] = 1
  for (let i = 1, l = 1; i < n; i++) {
    dp[p.charCodeAt(i) - 97] = Math.max(dp[p.charCodeAt(i) - 97], (p.charCodeAt(i) - p.charCodeAt(i - 1) + 26) % 26 === 1 ? ++l : l = 1)
  }
  let sum = 0
  for (let i = 0; i < 26; i++) sum += dp[i]
  return sum
};
func findSubstringInWraproundString(p string) int {
  n, dp, sum := len(p), make([]int, 26), 0
  dp[p[0] - 97] = 1
  for i, l := 1, 1; i < n; i++ {
    if (p[i] - p[i - 1] + 26) % 26 == 1 {
      l++
    } else {
      l = 1
    }
    dp[p[i] - 97] = max(dp[p[i] - 97], l)
  }
  for _, v := range dp {
    sum += v
  }
  return sum
}
func max(a, b int) int {
  if a > b {
    return a
  }
  return b
}
class Solution {
  function findSubstringInWraproundString($p) {
    $n = strlen($p);
    $dp = array_fill(0, 26, 0);
    $dp[ord($p[0]) - 97] = 1;
    for ($i = $l = 1; $i < $n; $i++) {
      $dp[ord($p[$i]) - 97] = max($dp[ord($p[$i]) - 97], (ord($p[$i]) - ord($p[$i - 1]) + 26) % 26 === 1 ? ++$l : $l = 1);
    }
    $sum = 0;
    for ($i = 0; $i < 26; $i++) $sum += $dp[$i];
    return $sum;
  }
}
class Solution(object):
  def findSubstringInWraproundString(self, p):
    dp = [0] * 26
    dp[ord(p[0]) - 97] = 1
    l = 1
    for i in range(1, len(p)):
      l = l + 1 if (ord(p[i]) - ord(p[i - 1])) % 26 == 1 else 1
      dp[ord(p[i]) - 97] = max(dp[ord(p[i]) - 97], l)
    return sum(dp)
class Solution:
  def findSubstringInWraproundString(self, p: str) -> int:
    dp = defaultdict(int)
    dp[ord(p[0]) - 97] = 1
    l = 1
    for i in range(1, len(p)):
      l = l + 1 if (ord(p[i]) - ord(p[i - 1])) % 26 == 1 else 1
      dp[ord(p[i]) - 97] = max(dp[ord(p[i]) - 97], l)
    return sum(dp.values())
class Solution {
  public int findSubstringInWraproundString(String p) {
    int n = p.length();
    int[] dp = new int[26];
    dp[p.charAt(0) - 97] = 1;
    for (int i = 1, l = 1; i < n; i++) {
      l = (p.charAt(i) - p.charAt(i - 1) + 26) % 26 == 1 ? l + 1 : 1;
      dp[p.charAt(i) - 97] = Math.max(dp[p.charAt(i) - 97], l);
    }
    return Arrays.stream(dp).sum();
  }
}

字符串操作、正则(零宽断言):2种方法求解《929. 独特的电子邮件地址》
字符串操作、正则(零宽断言),2种方法求解《929. 独特的电子邮件地址》
回溯 + 动态规划(掩码 · 状态压缩):2 方法求解《473. 火柴拼正方形》
回溯 + 动态规划(掩码 · 状态压缩),2 方法求解《473. 火柴拼正方形》
顺序遍历,正则:2 解法求解《468. 验证IP地址》
顺序遍历,正则,2 解法求解《468. 验证IP地址》