Welcome to Subscribe On Youtube
Formatted question description: https://leetcode.ca/all/2213.html
2213. Longest Substring of One Repeating Character
- Difficulty: Hard.
- Related Topics: Array, String, Segment Tree, Ordered Set.
- Similar Questions: Merge Intervals, Longest Repeating Character Replacement, Consecutive Characters, Create Sorted Array through Instructions.
Problem
You are given a 0-indexed string s
. You are also given a 0-indexed string queryCharacters
of length k
and a 0-indexed array of integer indices queryIndices
of length k
, both of which are used to describe k
queries.
The ith
query updates the character in s
at index queryIndices[i]
to the character queryCharacters[i]
.
Return an array lengths
of length **k
where** lengths[i]
is the **length of the longest substring of s
consisting of only one repeating character after the** ith
query** is performed.**
Example 1:
Input: s = "babacc", queryCharacters = "bcb", queryIndices = [1,3,3]
Output: [3,3,4]
Explanation:
- 1st query updates s = "bbbacc". The longest substring consisting of one repeating character is "bbb" with length 3.
- 2nd query updates s = "bbbccc".
The longest substring consisting of one repeating character can be "bbb" or "ccc" with length 3.
- 3rd query updates s = "bbbbcc". The longest substring consisting of one repeating character is "bbbb" with length 4.
Thus, we return [3,3,4].
Example 2:
Input: s = "abyzz", queryCharacters = "aa", queryIndices = [2,1]
Output: [2,3]
Explanation:
- 1st query updates s = "abazz". The longest substring consisting of one repeating character is "zz" with length 2.
- 2nd query updates s = "aaazz". The longest substring consisting of one repeating character is "aaa" with length 3.
Thus, we return [2,3].
Constraints:
-
1 <= s.length <= 105
-
s
consists of lowercase English letters. -
k == queryCharacters.length == queryIndices.length
-
1 <= k <= 105
-
queryCharacters
consists of lowercase English letters. -
0 <= queryIndices[i] < s.length
Solution
-
class Solution { static class TreeNode { int start; int end; char leftChar; int leftCharLen; char rightChar; int rightCharLen; int max; TreeNode left; TreeNode right; TreeNode(int start, int end) { this.start = start; this.end = end; left = null; right = null; } } public int[] longestRepeating(String s, String queryCharacters, int[] queryIndices) { char[] sChar = s.toCharArray(); char[] qChar = queryCharacters.toCharArray(); TreeNode root = buildTree(sChar, 0, sChar.length - 1); int[] result = new int[qChar.length]; for (int i = 0; i < qChar.length; i++) { updateTree(root, queryIndices[i], qChar[i]); if (root != null) { result[i] = root.max; } } return result; } private TreeNode buildTree(char[] s, int from, int to) { if (from > to) { return null; } TreeNode root = new TreeNode(from, to); if (from == to) { root.max = 1; root.rightChar = root.leftChar = s[from]; root.leftCharLen = root.rightCharLen = 1; return root; } int middle = from + (to - from) / 2; root.left = buildTree(s, from, middle); root.right = buildTree(s, middle + 1, to); updateNode(root); return root; } private void updateTree(TreeNode root, int index, char c) { if (root == null || root.start > index || root.end < index) { return; } if (root.start == index && root.end == index) { root.leftChar = root.rightChar = c; return; } updateTree(root.left, index, c); updateTree(root.right, index, c); updateNode(root); } private void updateNode(TreeNode root) { if (root == null) { return; } root.leftChar = root.left.leftChar; root.leftCharLen = root.left.leftCharLen; root.rightChar = root.right.rightChar; root.rightCharLen = root.right.rightCharLen; root.max = Math.max(root.left.max, root.right.max); if (root.left.rightChar == root.right.leftChar) { int len = root.left.rightCharLen + root.right.leftCharLen; if (root.left.leftChar == root.left.rightChar && root.left.leftCharLen == root.left.end - root.left.start + 1) { root.leftCharLen = len; } if (root.right.leftChar == root.right.rightChar && root.right.leftCharLen == root.right.end - root.right.start + 1) { root.rightCharLen = len; } root.max = Math.max(root.max, len); } } } ############ class Node { int l; int r; int size; int lmx; int rmx; int mx; char lc; char rc; } class SegmentTree { private String s; private Node[] tr; public SegmentTree(String s) { int n = s.length(); this.s = s; tr = new Node[n << 2]; for (int i = 0; i < tr.length; ++i) { tr[i] = new Node(); } build(1, 1, n); } public void build(int u, int l, int r) { tr[u].l = l; tr[u].r = r; if (l == r) { tr[u].lmx = 1; tr[u].rmx = 1; tr[u].mx = 1; tr[u].size = 1; tr[u].lc = s.charAt(l - 1); tr[u].rc = s.charAt(l - 1); return; } int mid = (l + r) >> 1; build(u << 1, l, mid); build(u << 1 | 1, mid + 1, r); pushup(u); } void modify(int u, int x, char v) { if (tr[u].l == x && tr[u].r == x) { tr[u].lc = v; tr[u].rc = v; return; } int mid = (tr[u].l + tr[u].r) >> 1; if (x <= mid) { modify(u << 1, x, v); } else { modify(u << 1 | 1, x, v); } pushup(u); } Node query(int u, int l, int r) { if (tr[u].l >= l && tr[u].r <= r) { return tr[u]; } int mid = (tr[u].l + tr[u].r) >> 1; if (r <= mid) { return query(u << 1, l, r); } if (l > mid) { return query(u << 1 | 1, l, r); } Node ans = new Node(); Node left = query(u << 1, l, r); Node right = query(u << 1 | 1, l, r); pushup(ans, left, right); return ans; } void pushup(Node root, Node left, Node right) { root.lc = left.lc; root.rc = right.rc; root.size = left.size + right.size; root.mx = Math.max(left.mx, right.mx); root.lmx = left.lmx; root.rmx = right.rmx; if (left.rc == right.lc) { if (left.lmx == left.size) { root.lmx += right.lmx; } if (right.rmx == right.size) { root.rmx += left.rmx; } root.mx = Math.max(root.mx, left.rmx + right.lmx); } } void pushup(int u) { pushup(tr[u], tr[u << 1], tr[u << 1 | 1]); } } class Solution { public int[] longestRepeating(String s, String queryCharacters, int[] queryIndices) { SegmentTree tree = new SegmentTree(s); int k = queryCharacters.length(); int[] ans = new int[k]; for (int i = 0; i < k; ++i) { int x = queryIndices[i] + 1; char c = queryCharacters.charAt(i); tree.modify(1, x, c); ans[i] = tree.query(1, 1, s.length()).mx; } return ans; } }
-
class Node: def __init__(self): self.l = 0 self.r = 0 self.lmx = 0 self.rmx = 0 self.mx = 0 self.size = 0 self.lc = None self.rc = None N = 100010 tr = [Node() for _ in range(N << 2)] class SegmentTree: def __init__(self, s): n = len(s) self.s = s self.build(1, 1, n) def build(self, u, l, r): tr[u].l = l tr[u].r = r if l == r: tr[u].lmx = tr[u].rmx = tr[u].mx = tr[u].size = 1 tr[u].lc = tr[u].rc = self.s[l - 1] return mid = (l + r) >> 1 self.build(u << 1, l, mid) self.build(u << 1 | 1, mid + 1, r) self.pushup(u) def modify(self, u, x, v): if tr[u].l == x and tr[u].r == x: tr[u].lc = tr[u].rc = v return mid = (tr[u].l + tr[u].r) >> 1 if x <= mid: self.modify(u << 1, x, v) else: self.modify(u << 1 | 1, x, v) self.pushup(u) def query(self, u, l, r): if tr[u].l >= l and tr[u].r <= r: return tr[u] mid = (tr[u].l + tr[u].r) >> 1 if r <= mid: return self.query(u << 1, l, r) if l > mid: return self.query(u << 1 | 1, l, r) left, right = self.query(u << 1, l, r), self.query(u << 1 | 1, l, r) ans = Node() self._pushup(ans, left, right) return ans def _pushup(self, root, left, right): root.lc, root.rc = left.lc, right.rc root.size = left.size + right.size root.mx = max(left.mx, right.mx) root.lmx, root.rmx = left.lmx, right.rmx if left.rc == right.lc: if left.lmx == left.size: root.lmx += right.lmx if right.rmx == right.size: root.rmx += left.rmx root.mx = max(root.mx, left.rmx + right.lmx) def pushup(self, u): self._pushup(tr[u], tr[u << 1], tr[u << 1 | 1]) class Solution: def longestRepeating( self, s: str, queryCharacters: str, queryIndices: List[int] ) -> List[int]: tree = SegmentTree(s) k = len(queryIndices) ans = [] for i, c in enumerate(queryCharacters): x = queryIndices[i] + 1 tree.modify(1, x, c) ans.append(tree.query(1, 1, len(s)).mx) return ans ############ # 2213. Longest Substring of One Repeating Character # https://leetcode.com/problems/longest-substring-of-one-repeating-character/ from sortedcontainers import SortedList class Solution: def longestRepeating(self, s: str, qc: str, qi: List[int]) -> List[int]: M = 10 ** 6 n = len(s) k = len(qc) s = list(s) sl = SortedList() h = SortedList() curr = 0 for x, group in groupby(s): length = sum(1 for c in group) sl.add((curr, curr + length - 1)) h.add(length) curr += length def add(x, y): sl.add((x, y)) h.add(y - x + 1) def remove(x, y): sl.remove((x, y)) h.remove(y - x + 1) def split(i): index = sl.bisect_right((i, M)) - 1 left, right = sl[index] remove(left, right) if left != i: add(left, i - 1) add(i, i) if right != i: add(i + 1, right) def merge(index): if index + 1 >= len(sl): return left1, right1 = sl[index] left2, right2 = sl[index + 1] if s[right1] != s[left2]: return remove(left1, right1) remove(left2, right2) add(left1, right2) res = [] for i, c in zip(qi, qc): if s[i] == c: res.append(h[-1]) continue split(i) index = sl.bisect_right((i, M)) - 1 s[i] = c merge(index) if index - 1 >= 0: merge(index - 1) res.append(h[-1]) return res
-
class Node { public: int l, r, size, lmx, rmx, mx; char lc, rc; }; class SegmentTree { private: string s; vector<Node*> tr; public: SegmentTree(string& s) { this->s = s; int n = s.size(); tr.resize(n << 2); for (int i = 0; i < tr.size(); ++i) tr[i] = new Node(); build(1, 1, n); } void build(int u, int l, int r) { tr[u]->l = l; tr[u]->r = r; if (l == r) { tr[u]->lmx = tr[u]->rmx = tr[u]->mx = tr[u]->size = 1; tr[u]->lc = tr[u]->rc = s[l - 1]; return; } int mid = (l + r) >> 1; build(u << 1, l, mid); build(u << 1 | 1, mid + 1, r); pushup(u); } void modify(int u, int x, char v) { if (tr[u]->l == x && tr[u]->r == x) { tr[u]->lc = tr[u]->rc = v; return; } int mid = (tr[u]->l + tr[u]->r) >> 1; if (x <= mid) modify(u << 1, x, v); else modify(u << 1 | 1, x, v); pushup(u); } Node* query(int u, int l, int r) { if (tr[u]->l >= l && tr[u]->r <= r) return tr[u]; int mid = (tr[u]->l + tr[u]->r) >> 1; if (r <= mid) return query(u << 1, l, r); if (l > mid) query(u << 1 | 1, l, r); Node* ans = new Node(); Node* left = query(u << 1, l, r); Node* right = query(u << 1 | 1, l, r); pushup(ans, left, right); return ans; } void pushup(Node* root, Node* left, Node* right) { root->lc = left->lc; root->rc = right->rc; root->size = left->size + right->size; root->mx = max(left->mx, right->mx); root->lmx = left->lmx; root->rmx = right->rmx; if (left->rc == right->lc) { if (left->lmx == left->size) root->lmx += right->lmx; if (right->rmx == right->size) root->rmx += left->rmx; root->mx = max(root->mx, left->rmx + right->lmx); } } void pushup(int u) { pushup(tr[u], tr[u << 1], tr[u << 1 | 1]); } }; class Solution { public: vector<int> longestRepeating(string s, string queryCharacters, vector<int>& queryIndices) { SegmentTree* tree = new SegmentTree(s); int k = queryCharacters.size(); vector<int> ans(k); for (int i = 0; i < k; ++i) { int x = queryIndices[i] + 1; tree->modify(1, x, queryCharacters[i]); ans[i] = tree->query(1, 1, s.size())->mx; } return ans; } };
-
type segmentTree struct { str []byte mx []int lmx []int rmx []int } func newSegmentTree(s string) *segmentTree { n := len(s) t := &segmentTree{ str: []byte(s), mx: make([]int, n<<2), lmx: make([]int, n<<2), rmx: make([]int, n<<2), } t.build(0, 0, n-1) return t } func (t *segmentTree) build(x, l, r int) { if l == r { t.lmx[x] = 1 t.rmx[x] = 1 t.mx[x] = 1 return } m := int(uint(l+r) >> 1) t.build(x*2+1, l, m) t.build(x*2+2, m+1, r) t.pushup(x, l, m, r) } func (t *segmentTree) pushup(x, l, m, r int) { lch, rch := x*2+1, x*2+2 t.lmx[x] = t.lmx[lch] t.rmx[x] = t.rmx[rch] t.mx[x] = max(t.mx[lch], t.mx[rch]) // can be merged if t.str[m] == t.str[m+1] { if t.lmx[lch] == m-l+1 { t.lmx[x] += t.lmx[rch] } if t.rmx[rch] == r-m { t.rmx[x] += t.rmx[lch] } t.mx[x] = max(t.mx[x], t.rmx[lch]+t.lmx[rch]) } } func (t *segmentTree) update(x, l, r, pos int, val byte) { if l == r { t.str[pos] = val return } m := int(uint(l+r) >> 1) if pos <= m { t.update(x*2+1, l, m, pos, val) } else { t.update(x*2+2, m+1, r, pos, val) } t.pushup(x, l, m, r) } func max(x, y int) int { if x > y { return x } return y } func longestRepeating(s string, queryCharacters string, queryIndices []int) []int { ans := make([]int, len(queryCharacters)) t := newSegmentTree(s) n := len(s) for i, c := range queryCharacters { t.update(0, 0, n-1, queryIndices[i], byte(c)) ans[i] = t.mx[0] } return ans }
Explain:
nope.
Complexity:
- Time complexity : O(n).
- Space complexity : O(n).