LeetCode-Solutions-in-Cpp17

Solutions to high-frequency interview questions of LeetCode in C++17, taking into account both efficiency and comprehensibility.


Project maintained by downdemo Hosted on GitHub Pages — Theme by mattgraham
s = abba => str = #a#b#b#a#

#a#b#b#a#
012345678

// 均可以从单个字符出发向两边扩展
0 # => #
1 a => #a#
2 # => #
3 b => #b#
4 # => b#b => #b#b# => a#b#b#a => #a#b#b#a#
5 b => #b#
6 # => #
7 a => #a#
8 # => #
class Solution {
 public:
  string longestPalindrome(string s) {
    string str{'#'};
    for (auto& x : s) {
      str += x;
      str += '#';
    }  // str为扩展后的字符串
    string res;
    int len = 0;
    for (int i = 0; i < size(str); ++i) {
      int l = i;
      int r = i;
      while (str[l] == str[r]) {
        --l;
        ++r;
        if (l < 0 || r >= size(str)) {
          break;
        }
      }
      if (r - l > len) {
        len = r - l;
        res = str.substr(l + 1, r - l - 1);
      }
    }
    res.erase(remove(begin(res), end(res), '#'), end(res));
    return res;
  }
};
#a#b#b#a#
012345678

i    = 0 1 2 3 4 5 6 7 8
p[i] = 1 2 1 2 5 2 1 2 1
// 可以发现 p[i] - 1 就是原来的回文子串长度,最大回文子串长度就是 5 - 1 = 4
#a#b#b#a#
012345678

i    = 0 1 2 3 4 5 6 7 8
p[i] = 1 2 1 2 5 2 1 2 1
mx   = 1 3 3 5 9 7 7 9 9
// i < mx
__________id__________mx
__j_______id_______i__mx  // j 为 i 关于 id 的对称点,j = id - (i - id) = 2 * id - i
// if (i < mx && p[j] > mx - i) p[i] = mx - i;
 ___________id___________mx
---j---_____id________i__mx  // 必定 p[i] = mx - i

// 如果 p[i] 右边界超出 mx 的话,即 p[i] > mx - i
---j---_____id_____---i---mx  // id 的右边界应该超出 mx,与 mx 是最大右边界的前提矛盾
// if (i < mx && p[j] < mx - i) p[i] = p[j];
___________id___________mx
_-j-_______id________i__mx  // 必定p[i] = p[j]
// if (i < mx && p[j] == mx - i) p[i] = p[j]; // 仍可能增加
___________id___________mx
--j--______id________i__mx  // p[i] >= p[j] 或 mx - i,p[i] 可以继续增加,还需要向两边扩展计算 p[i]
if (i < mx) {
  if (p[2 * id - i] < mx - i) {
    p[i] = p[2 * id - i];
  }
  if (p[2 * id - i] > mx - i) {
    p[i] = mx - i;
  }
  if (p[2 * id - i] == mx - i) {
    p[i] = mx - i;
    while (str[i - p[i]] == str[i + p[i]]) {
      ++p[i];
    }
  }
}
if (i == mx) {
  p[i] = 1;
  while (i >= p[i] && str[i - p[i]] == str[i + p[i]]) {
    ++p[i];
  }
}
if (i < mx) {
  if (p[2 * id - i] < mx - i) {
    p[i] = p[2 * id - i];
  }
  if (p[2 * id - i] > mx - i) {
    p[i] = mx - i;
  }
  if (p[2 * id - i] == mx - i) {
    p[i] = mx - i;
    while (i >= p[i] &&  // 确保 i - p[i] >= 0 防越界
           str[i - p[i]] == str[i + p[i]]) {
      ++p[i];
    }
  }
} else if (i == mx) {
  p[i] = 1;
  while (i >= p[i] && str[i - p[i]] == str[i + p[i]]) {
    ++p[i];
  }
}
if (i < mx) {
  p[i] = min(p[2 * id - i], mx - i);
} else if (i == mx) {
  p[i] = 1;
}
while (i >= p[i] && str[i - p[i]] == str[i + p[i]]) {
  ++p[i];
}
if (mx < i + p[i]) {
  id = i;
  mx = i + p[i];
}
class Solution {
 public:
  string longestPalindrome(string s) {
    if (size(s) <= 1) {
      return s;
    }
    string str{"#"};
    for (auto& x : s) {
      str += x;
      str += '#';
    }  // str为扩展后的字符串
    int sz = size(str);
    vector<int> p(sz);
    int start = 0;   // 最长回文子串首字符在原字符串中的下标
    int maxLen = 0;  // 最长回文子串的长度

    int id = 0;
    int mx = 0;  // 最大右边界 = p[id] + id

    for (int i = 0; i < sz; ++i) {
      if (i < mx) {
        p[i] = min(p[2 * id - i], mx - i);
      } else if (i == mx) {
        p[i] = 1;
      }
      while (i >= p[i] && str[i - p[i]] == str[i + p[i]]) {
        ++p[i];
      }
      if (mx < i + p[i]) {  // 检查是否超出右边界
        id = i;
        mx = i + p[i];
      }
      if (p[i] - 1 > maxLen) {  // p[i] - 1 是回文子串的长度
        start = i;
        maxLen = p[i] - 1;
      }
    }
    return s.substr((start - p[start] + 1) / 2, maxLen);
  }
};