diff --git a/solution/0300-0399/0358.Rearrange String k Distance Apart/README.md b/solution/0300-0399/0358.Rearrange String k Distance Apart/README.md index 55366afd9dd02..f669b623a9e65 100644 --- a/solution/0300-0399/0358.Rearrange String k Distance Apart/README.md +++ b/solution/0300-0399/0358.Rearrange String k Distance Apart/README.md @@ -29,7 +29,7 @@ tags:
 输入: s = "aabbcc", k = 3
-输出: "abcabc" 
+输出: "abcabc"
 解释: 相同的字母在新的字符串中间隔至少 3 个单位距离。
 
@@ -37,7 +37,7 @@ tags:
 输入: s = "aaabc", k = 3
-输出: "" 
+输出: ""
 解释: 没有办法找到可能的重排结果。
 
@@ -67,13 +67,13 @@ tags: ### 方法一:贪心 + 哈希表 + 优先队列(大根堆) -先用哈希表 `cnt` 统计每个字母出现的次数,然后构建一个大根堆 `pq`,其中每个元素是一个 `(v, c)` 的元组,其中 `c` 是字母,`v` 是字母出现的次数。 +我们用一个哈希表或数组 $\textit{cnt}$ 来统计字符串中每个字母出现的次数,然后用一个大根堆 $\textit{pq}$ 来存储每个字母及其出现次数。堆中的每个元素是一个二元组 $(v, c)$,其中 $v$ 和 $c$ 分别表示字母出现的次数和字母本身。 -重排字符串时,我们每次从堆顶弹出一个元素 `(v, c)`,将 `c` 添加到结果字符串中,并将 `(v-1, c)` 放入队列 `q` 中。当队列 `q` 的长度达到 $k$ 及以上时,弹出队首元素,若此时 `v` 大于 0,则将队首元素放入堆中。循环,直至堆为空。 +在重排字符串时,我们每次从堆顶弹出一个元素 $(v, c)$,将字母 $c$ 添加到结果字符串中,并将 $(v-1, c)$ 放入一个队列 $\textit{q}$ 中。当队列 $\textit{q}$ 的长度达到 $k$ 及以上时,弹出队首元素,若此时 $v$ 大于 $0$,则将队首元素重新放入堆中。重复该过程,直到堆为空。 -最后判断结果字符串的长度,若与 `s` 长度相等,则返回结果字符串,否则返回空串。 +最后,我们判断结果字符串的长度是否与原字符串相等,若相等则返回结果字符串,否则返回空串。 -时间复杂度 $O(n\log n)$,其中 $n$ 是字符串 `s` 的长度。 +时间复杂度为 $O(n \log n)$,其中 $n$ 是字符串的长度。空间复杂度 $O(|\Sigma|)$,其中 $|\Sigma|$ 是字符集的大小,本题中 $|\Sigma| = 26$。 相似题目: @@ -86,20 +86,20 @@ tags: ```python class Solution: def rearrangeString(self, s: str, k: int) -> str: - h = [(-v, c) for c, v in Counter(s).items()] - heapify(h) + cnt = Counter(s) + pq = [(-v, c) for c, v in cnt.items()] + heapify(pq) q = deque() ans = [] - while h: - v, c = heappop(h) - v *= -1 + while pq: + v, c = heappop(pq) ans.append(c) - q.append((v - 1, c)) + q.append((v + 1, c)) if len(q) >= k: - w, c = q.popleft() - if w: - heappush(h, (-w, c)) - return "" if len(ans) != len(s) else "".join(ans) + e = q.popleft() + if e[0]: + heappush(pq, e) + return "" if len(ans) < len(s) else "".join(ans) ``` #### Java @@ -107,13 +107,12 @@ class Solution: ```java class Solution { public String rearrangeString(String s, int k) { - int n = s.length(); int[] cnt = new int[26]; for (char c : s.toCharArray()) { ++cnt[c - 'a']; } PriorityQueue pq = new PriorityQueue<>((a, b) -> b[0] - a[0]); - for (int i = 0; i < 26; ++i) { + for (int i = 0; i < cnt.length; ++i) { if (cnt[i] > 0) { pq.offer(new int[] {cnt[i], i}); } @@ -122,9 +121,9 @@ class Solution { StringBuilder ans = new StringBuilder(); while (!pq.isEmpty()) { var p = pq.poll(); - int v = p[0], c = p[1]; - ans.append((char) ('a' + c)); - q.offer(new int[] {v - 1, c}); + p[0] -= 1; + ans.append((char) ('a' + p[1])); + q.offerLast(p); if (q.size() >= k) { p = q.pollFirst(); if (p[0] > 0) { @@ -132,7 +131,7 @@ class Solution { } } } - return ans.length() == n ? ans.toString() : ""; + return ans.length() < s.length() ? "" : ans.toString(); } } ``` @@ -143,26 +142,36 @@ class Solution { class Solution { public: string rearrangeString(string s, int k) { - unordered_map cnt; - for (char c : s) ++cnt[c]; - priority_queue> pq; - for (auto& [c, v] : cnt) pq.push({v, c}); - queue> q; + vector cnt(26, 0); + for (char c : s) { + ++cnt[c - 'a']; + } + + priority_queue> pq; + for (int i = 0; i < 26; ++i) { + if (cnt[i] > 0) { + pq.emplace(cnt[i], i); + } + } + + queue> q; string ans; while (!pq.empty()) { - auto [v, c] = pq.top(); + auto p = pq.top(); pq.pop(); - ans += c; - q.push({v - 1, c}); + p.first -= 1; + ans.push_back('a' + p.second); + q.push(p); if (q.size() >= k) { - auto p = q.front(); + p = q.front(); q.pop(); - if (p.first) { + if (p.first > 0) { pq.push(p); } } } - return ans.size() == s.size() ? ans : ""; + + return ans.size() < s.size() ? "" : ans; } }; ``` @@ -171,50 +180,80 @@ public: ```go func rearrangeString(s string, k int) string { - cnt := map[byte]int{} - for i := range s { - cnt[s[i]]++ + cnt := [26]int{} + for _, c := range s { + cnt[c-'a']++ } - pq := hp{} - for c, v := range cnt { - heap.Push(&pq, pair{v, c}) + pq := priorityqueue.NewWith(func(a, b any) int { + x := a.([2]int) + y := b.([2]int) + return y[0] - x[0] + }) + + for i := 0; i < 26; i++ { + if cnt[i] > 0 { + pq.Enqueue([2]int{cnt[i], i}) + } } - ans := []byte{} - q := []pair{} - for len(pq) > 0 { - p := heap.Pop(&pq).(pair) - v, c := p.v, p.c - ans = append(ans, c) - q = append(q, pair{v - 1, c}) + + var q [][2]int + var ans strings.Builder + + for pq.Size() > 0 { + p, _ := pq.Dequeue() + pair := p.([2]int) + pair[0]-- + ans.WriteByte(byte('a' + pair[1])) + q = append(q, pair) + if len(q) >= k { - p = q[0] + front := q[0] q = q[1:] - if p.v > 0 { - heap.Push(&pq, p) + if front[0] > 0 { + pq.Enqueue(front) } } } - if len(ans) == len(s) { - return string(ans) + + if ans.Len() < len(s) { + return "" } - return "" + return ans.String() } +``` -type pair struct { - v int - c byte -} +#### TypeScript + +```ts +export function rearrangeString(s: string, k: number): string { + const cnt: number[] = Array(26).fill(0); + for (const c of s) { + cnt[c.charCodeAt(0) - 'a'.charCodeAt(0)]++; + } -type hp []pair + const pq = new PriorityQueue<[number, number]>((a, b) => b[0] - a[0]); + for (let i = 0; i < 26; i++) { + if (cnt[i] > 0) { + pq.enqueue([cnt[i], i]); + } + } -func (h hp) Len() int { return len(h) } -func (h hp) Less(i, j int) bool { - a, b := h[i], h[j] - return a.v > b.v + const q: [number, number][] = []; + const ans: string[] = []; + while (!pq.isEmpty()) { + const [count, idx] = pq.dequeue()!; + const newCount = count - 1; + ans.push(String.fromCharCode('a'.charCodeAt(0) + idx)); + q.push([newCount, idx]); + if (q.length >= k) { + const [frontCount, frontIdx] = q.shift()!; + if (frontCount > 0) { + pq.enqueue([frontCount, frontIdx]); + } + } + } + return ans.length < s.length ? '' : ans.join(''); } -func (h hp) Swap(i, j int) { h[i], h[j] = h[j], h[i] } -func (h *hp) Push(v any) { *h = append(*h, v.(pair)) } -func (h *hp) Pop() any { a := *h; v := a[len(a)-1]; *h = a[:len(a)-1]; return v } ``` diff --git a/solution/0300-0399/0358.Rearrange String k Distance Apart/README_EN.md b/solution/0300-0399/0358.Rearrange String k Distance Apart/README_EN.md index e07f9869ecae5..a5497acd9181e 100644 --- a/solution/0300-0399/0358.Rearrange String k Distance Apart/README_EN.md +++ b/solution/0300-0399/0358.Rearrange String k Distance Apart/README_EN.md @@ -63,7 +63,19 @@ tags: -### Solution 1 +### Solution 1: Greedy + Hash Table + Priority Queue (Max Heap) + +We use a hash table or array $\textit{cnt}$ to count the occurrences of each character in the string. Then, we use a max heap $\textit{pq}$ to store each character and its count. Each element in the heap is a tuple $(v, c)$, where $v$ is the count and $c$ is the character. + +When rearranging the string, we repeatedly pop the top element $(v, c)$ from the heap, add character $c$ to the result string, and push $(v-1, c)$ into a queue $\textit{q}$. When the length of the queue $\textit{q}$ reaches $k$ or more, we pop the front element; if its $v$ is greater than $0$, we push it back into the heap. Repeat this process until the heap is empty. + +Finally, we check whether the length of the result string equals the original string. If so, we return the result string; otherwise, we return an empty string. + +The time complexity is $O(n \log n)$, where $n$ is the length of the string. The space complexity is $O(|\Sigma|)$, where $|\Sigma|$ is the size of the character set, which is $26$ in this problem. + +Related problems: + +- [767. Reorganize String](https://github.com/doocs/leetcode/blob/main/solution/0700-0799/0767.Reorganize%20String/README.md) @@ -72,20 +84,20 @@ tags: ```python class Solution: def rearrangeString(self, s: str, k: int) -> str: - h = [(-v, c) for c, v in Counter(s).items()] - heapify(h) + cnt = Counter(s) + pq = [(-v, c) for c, v in cnt.items()] + heapify(pq) q = deque() ans = [] - while h: - v, c = heappop(h) - v *= -1 + while pq: + v, c = heappop(pq) ans.append(c) - q.append((v - 1, c)) + q.append((v + 1, c)) if len(q) >= k: - w, c = q.popleft() - if w: - heappush(h, (-w, c)) - return "" if len(ans) != len(s) else "".join(ans) + e = q.popleft() + if e[0]: + heappush(pq, e) + return "" if len(ans) < len(s) else "".join(ans) ``` #### Java @@ -93,13 +105,12 @@ class Solution: ```java class Solution { public String rearrangeString(String s, int k) { - int n = s.length(); int[] cnt = new int[26]; for (char c : s.toCharArray()) { ++cnt[c - 'a']; } PriorityQueue pq = new PriorityQueue<>((a, b) -> b[0] - a[0]); - for (int i = 0; i < 26; ++i) { + for (int i = 0; i < cnt.length; ++i) { if (cnt[i] > 0) { pq.offer(new int[] {cnt[i], i}); } @@ -108,9 +119,9 @@ class Solution { StringBuilder ans = new StringBuilder(); while (!pq.isEmpty()) { var p = pq.poll(); - int v = p[0], c = p[1]; - ans.append((char) ('a' + c)); - q.offer(new int[] {v - 1, c}); + p[0] -= 1; + ans.append((char) ('a' + p[1])); + q.offerLast(p); if (q.size() >= k) { p = q.pollFirst(); if (p[0] > 0) { @@ -118,7 +129,7 @@ class Solution { } } } - return ans.length() == n ? ans.toString() : ""; + return ans.length() < s.length() ? "" : ans.toString(); } } ``` @@ -129,26 +140,36 @@ class Solution { class Solution { public: string rearrangeString(string s, int k) { - unordered_map cnt; - for (char c : s) ++cnt[c]; - priority_queue> pq; - for (auto& [c, v] : cnt) pq.push({v, c}); - queue> q; + vector cnt(26, 0); + for (char c : s) { + ++cnt[c - 'a']; + } + + priority_queue> pq; + for (int i = 0; i < 26; ++i) { + if (cnt[i] > 0) { + pq.emplace(cnt[i], i); + } + } + + queue> q; string ans; while (!pq.empty()) { - auto [v, c] = pq.top(); + auto p = pq.top(); pq.pop(); - ans += c; - q.push({v - 1, c}); + p.first -= 1; + ans.push_back('a' + p.second); + q.push(p); if (q.size() >= k) { - auto p = q.front(); + p = q.front(); q.pop(); - if (p.first) { + if (p.first > 0) { pq.push(p); } } } - return ans.size() == s.size() ? ans : ""; + + return ans.size() < s.size() ? "" : ans; } }; ``` @@ -157,50 +178,80 @@ public: ```go func rearrangeString(s string, k int) string { - cnt := map[byte]int{} - for i := range s { - cnt[s[i]]++ + cnt := [26]int{} + for _, c := range s { + cnt[c-'a']++ } - pq := hp{} - for c, v := range cnt { - heap.Push(&pq, pair{v, c}) + pq := priorityqueue.NewWith(func(a, b any) int { + x := a.([2]int) + y := b.([2]int) + return y[0] - x[0] + }) + + for i := 0; i < 26; i++ { + if cnt[i] > 0 { + pq.Enqueue([2]int{cnt[i], i}) + } } - ans := []byte{} - q := []pair{} - for len(pq) > 0 { - p := heap.Pop(&pq).(pair) - v, c := p.v, p.c - ans = append(ans, c) - q = append(q, pair{v - 1, c}) + + var q [][2]int + var ans strings.Builder + + for pq.Size() > 0 { + p, _ := pq.Dequeue() + pair := p.([2]int) + pair[0]-- + ans.WriteByte(byte('a' + pair[1])) + q = append(q, pair) + if len(q) >= k { - p = q[0] + front := q[0] q = q[1:] - if p.v > 0 { - heap.Push(&pq, p) + if front[0] > 0 { + pq.Enqueue(front) } } } - if len(ans) == len(s) { - return string(ans) + + if ans.Len() < len(s) { + return "" } - return "" + return ans.String() } +``` -type pair struct { - v int - c byte -} +#### TypeScript -type hp []pair +```ts +export function rearrangeString(s: string, k: number): string { + const cnt: number[] = Array(26).fill(0); + for (const c of s) { + cnt[c.charCodeAt(0) - 'a'.charCodeAt(0)]++; + } + + const pq = new PriorityQueue<[number, number]>((a, b) => b[0] - a[0]); + for (let i = 0; i < 26; i++) { + if (cnt[i] > 0) { + pq.enqueue([cnt[i], i]); + } + } -func (h hp) Len() int { return len(h) } -func (h hp) Less(i, j int) bool { - a, b := h[i], h[j] - return a.v > b.v + const q: [number, number][] = []; + const ans: string[] = []; + while (!pq.isEmpty()) { + const [count, idx] = pq.dequeue()!; + const newCount = count - 1; + ans.push(String.fromCharCode('a'.charCodeAt(0) + idx)); + q.push([newCount, idx]); + if (q.length >= k) { + const [frontCount, frontIdx] = q.shift()!; + if (frontCount > 0) { + pq.enqueue([frontCount, frontIdx]); + } + } + } + return ans.length < s.length ? '' : ans.join(''); } -func (h hp) Swap(i, j int) { h[i], h[j] = h[j], h[i] } -func (h *hp) Push(v any) { *h = append(*h, v.(pair)) } -func (h *hp) Pop() any { a := *h; v := a[len(a)-1]; *h = a[:len(a)-1]; return v } ``` diff --git a/solution/0300-0399/0358.Rearrange String k Distance Apart/Solution.cpp b/solution/0300-0399/0358.Rearrange String k Distance Apart/Solution.cpp index ecb559d9415a7..a1e9530f2a129 100644 --- a/solution/0300-0399/0358.Rearrange String k Distance Apart/Solution.cpp +++ b/solution/0300-0399/0358.Rearrange String k Distance Apart/Solution.cpp @@ -1,25 +1,35 @@ class Solution { public: string rearrangeString(string s, int k) { - unordered_map cnt; - for (char c : s) ++cnt[c]; - priority_queue> pq; - for (auto& [c, v] : cnt) pq.push({v, c}); - queue> q; + vector cnt(26, 0); + for (char c : s) { + ++cnt[c - 'a']; + } + + priority_queue> pq; + for (int i = 0; i < 26; ++i) { + if (cnt[i] > 0) { + pq.emplace(cnt[i], i); + } + } + + queue> q; string ans; while (!pq.empty()) { - auto [v, c] = pq.top(); + auto p = pq.top(); pq.pop(); - ans += c; - q.push({v - 1, c}); + p.first -= 1; + ans.push_back('a' + p.second); + q.push(p); if (q.size() >= k) { - auto p = q.front(); + p = q.front(); q.pop(); - if (p.first) { + if (p.first > 0) { pq.push(p); } } } - return ans.size() == s.size() ? ans : ""; + + return ans.size() < s.size() ? "" : ans; } -}; \ No newline at end of file +}; diff --git a/solution/0300-0399/0358.Rearrange String k Distance Apart/Solution.go b/solution/0300-0399/0358.Rearrange String k Distance Apart/Solution.go index 4f30bac82f95a..f70ce26b07057 100644 --- a/solution/0300-0399/0358.Rearrange String k Distance Apart/Solution.go +++ b/solution/0300-0399/0358.Rearrange String k Distance Apart/Solution.go @@ -1,45 +1,41 @@ func rearrangeString(s string, k int) string { - cnt := map[byte]int{} - for i := range s { - cnt[s[i]]++ + cnt := [26]int{} + for _, c := range s { + cnt[c-'a']++ } - pq := hp{} - for c, v := range cnt { - heap.Push(&pq, pair{v, c}) + pq := priorityqueue.NewWith(func(a, b any) int { + x := a.([2]int) + y := b.([2]int) + return y[0] - x[0] + }) + + for i := 0; i < 26; i++ { + if cnt[i] > 0 { + pq.Enqueue([2]int{cnt[i], i}) + } } - ans := []byte{} - q := []pair{} - for len(pq) > 0 { - p := heap.Pop(&pq).(pair) - v, c := p.v, p.c - ans = append(ans, c) - q = append(q, pair{v - 1, c}) + + var q [][2]int + var ans strings.Builder + + for pq.Size() > 0 { + p, _ := pq.Dequeue() + pair := p.([2]int) + pair[0]-- + ans.WriteByte(byte('a' + pair[1])) + q = append(q, pair) + if len(q) >= k { - p = q[0] + front := q[0] q = q[1:] - if p.v > 0 { - heap.Push(&pq, p) + if front[0] > 0 { + pq.Enqueue(front) } } } - if len(ans) == len(s) { - return string(ans) - } - return "" -} - -type pair struct { - v int - c byte -} -type hp []pair - -func (h hp) Len() int { return len(h) } -func (h hp) Less(i, j int) bool { - a, b := h[i], h[j] - return a.v > b.v + if ans.Len() < len(s) { + return "" + } + return ans.String() } -func (h hp) Swap(i, j int) { h[i], h[j] = h[j], h[i] } -func (h *hp) Push(v any) { *h = append(*h, v.(pair)) } -func (h *hp) Pop() any { a := *h; v := a[len(a)-1]; *h = a[:len(a)-1]; return v } \ No newline at end of file diff --git a/solution/0300-0399/0358.Rearrange String k Distance Apart/Solution.java b/solution/0300-0399/0358.Rearrange String k Distance Apart/Solution.java index f3a4fe65adea3..16ba2e7e5b568 100644 --- a/solution/0300-0399/0358.Rearrange String k Distance Apart/Solution.java +++ b/solution/0300-0399/0358.Rearrange String k Distance Apart/Solution.java @@ -1,12 +1,11 @@ class Solution { public String rearrangeString(String s, int k) { - int n = s.length(); int[] cnt = new int[26]; for (char c : s.toCharArray()) { ++cnt[c - 'a']; } PriorityQueue pq = new PriorityQueue<>((a, b) -> b[0] - a[0]); - for (int i = 0; i < 26; ++i) { + for (int i = 0; i < cnt.length; ++i) { if (cnt[i] > 0) { pq.offer(new int[] {cnt[i], i}); } @@ -15,9 +14,9 @@ public String rearrangeString(String s, int k) { StringBuilder ans = new StringBuilder(); while (!pq.isEmpty()) { var p = pq.poll(); - int v = p[0], c = p[1]; - ans.append((char) ('a' + c)); - q.offer(new int[] {v - 1, c}); + p[0] -= 1; + ans.append((char) ('a' + p[1])); + q.offerLast(p); if (q.size() >= k) { p = q.pollFirst(); if (p[0] > 0) { @@ -25,6 +24,6 @@ public String rearrangeString(String s, int k) { } } } - return ans.length() == n ? ans.toString() : ""; + return ans.length() < s.length() ? "" : ans.toString(); } -} \ No newline at end of file +} diff --git a/solution/0300-0399/0358.Rearrange String k Distance Apart/Solution.py b/solution/0300-0399/0358.Rearrange String k Distance Apart/Solution.py index c9b50afa78b6c..8e5d4cd98d73b 100644 --- a/solution/0300-0399/0358.Rearrange String k Distance Apart/Solution.py +++ b/solution/0300-0399/0358.Rearrange String k Distance Apart/Solution.py @@ -1,16 +1,16 @@ class Solution: def rearrangeString(self, s: str, k: int) -> str: - h = [(-v, c) for c, v in Counter(s).items()] - heapify(h) + cnt = Counter(s) + pq = [(-v, c) for c, v in cnt.items()] + heapify(pq) q = deque() ans = [] - while h: - v, c = heappop(h) - v *= -1 + while pq: + v, c = heappop(pq) ans.append(c) - q.append((v - 1, c)) + q.append((v + 1, c)) if len(q) >= k: - w, c = q.popleft() - if w: - heappush(h, (-w, c)) - return "" if len(ans) != len(s) else "".join(ans) + e = q.popleft() + if e[0]: + heappush(pq, e) + return "" if len(ans) < len(s) else "".join(ans) diff --git a/solution/0300-0399/0358.Rearrange String k Distance Apart/Solution.ts b/solution/0300-0399/0358.Rearrange String k Distance Apart/Solution.ts new file mode 100644 index 0000000000000..5db004b700c5e --- /dev/null +++ b/solution/0300-0399/0358.Rearrange String k Distance Apart/Solution.ts @@ -0,0 +1,29 @@ +export function rearrangeString(s: string, k: number): string { + const cnt: number[] = Array(26).fill(0); + for (const c of s) { + cnt[c.charCodeAt(0) - 'a'.charCodeAt(0)]++; + } + + const pq = new PriorityQueue<[number, number]>((a, b) => b[0] - a[0]); + for (let i = 0; i < 26; i++) { + if (cnt[i] > 0) { + pq.enqueue([cnt[i], i]); + } + } + + const q: [number, number][] = []; + const ans: string[] = []; + while (!pq.isEmpty()) { + const [count, idx] = pq.dequeue()!; + const newCount = count - 1; + ans.push(String.fromCharCode('a'.charCodeAt(0) + idx)); + q.push([newCount, idx]); + if (q.length >= k) { + const [frontCount, frontIdx] = q.shift()!; + if (frontCount > 0) { + pq.enqueue([frontCount, frontIdx]); + } + } + } + return ans.length < s.length ? '' : ans.join(''); +} diff --git a/solution/0300-0399/0359.Logger Rate Limiter/README.md b/solution/0300-0399/0359.Logger Rate Limiter/README.md index 863840fa2e499..e76cbfba8f9e0 100644 --- a/solution/0300-0399/0359.Logger Rate Limiter/README.md +++ b/solution/0300-0399/0359.Logger Rate Limiter/README.md @@ -67,7 +67,11 @@ logger.shouldPrintMessage(11, "foo"); // 11 >= 11 ,返回 true ,下一次 "f -### 方法一 +### 方法一:哈希表 + +我们用一个哈希表 $\textit{ts}$ 来存储每个消息的下一个可打印时间戳。在调用 `shouldPrintMessage` 方法时,我们检查当前时间戳是否大于等于消息的下一个可打印时间戳,若是则更新该消息的下一个可打印时间戳为当前时间戳加 10,并返回 `true`,否则返回 `false`。 + +时间复杂度 $O(1)$。空间复杂度 $O(m)$,其中 $m$ 是不同消息的数量。 @@ -75,22 +79,15 @@ logger.shouldPrintMessage(11, "foo"); // 11 >= 11 ,返回 true ,下一次 "f ```python class Logger: + def __init__(self): - """ - Initialize your data structure here. - """ - self.limiter = {} + self.ts = {} def shouldPrintMessage(self, timestamp: int, message: str) -> bool: - """ - Returns true if the message should be printed in the given timestamp, otherwise returns false. - If this method returns false, the message will not be printed. - The timestamp is in seconds granularity. - """ - t = self.limiter.get(message, 0) + t = self.ts.get(message, 0) if t > timestamp: return False - self.limiter[message] = timestamp + 10 + self.ts[message] = timestamp + 10 return True @@ -103,25 +100,17 @@ class Logger: ```java class Logger { + private Map ts = new HashMap<>(); - private Map limiter; - - /** Initialize your data structure here. */ public Logger() { - limiter = new HashMap<>(); } - /** - Returns true if the message should be printed in the given timestamp, otherwise returns - false. If this method returns false, the message will not be printed. The timestamp is in - seconds granularity. - */ public boolean shouldPrintMessage(int timestamp, String message) { - int t = limiter.getOrDefault(message, 0); - if (t > timestamp) { + int t = ts.getOrDefault(message, 0); + if (timestamp < t) { return false; } - limiter.put(message, timestamp + 10); + ts.put(message, timestamp + 10); return true; } } @@ -133,6 +122,59 @@ class Logger { */ ``` +#### C++ + +```cpp +class Logger { +public: + Logger() { + } + + bool shouldPrintMessage(int timestamp, string message) { + if (ts.contains(message) && ts[message] > timestamp) { + return false; + } + ts[message] = timestamp + 10; + return true; + } + +private: + unordered_map ts; +}; + +/** + * Your Logger object will be instantiated and called as such: + * Logger* obj = new Logger(); + * bool param_1 = obj->shouldPrintMessage(timestamp,message); + */ +``` + +#### Go + +```go +type Logger struct { + ts map[string]int +} + +func Constructor() Logger { + return Logger{ts: make(map[string]int)} +} + +func (this *Logger) ShouldPrintMessage(timestamp int, message string) bool { + if t, ok := this.ts[message]; ok && timestamp < t { + return false + } + this.ts[message] = timestamp + 10 + return true +} + +/** + * Your Logger object will be instantiated and called as such: + * obj := Constructor(); + * param_1 := obj.ShouldPrintMessage(timestamp,message); + */ +``` + #### JavaScript ```js @@ -146,8 +188,8 @@ var Logger = function () { /** * Returns true if the message should be printed in the given timestamp, otherwise returns false. If this method returns false, the message will not be printed. - The timestamp is in seconds granularity. - * @param {number} timestamp + The timestamp is in seconds granularity. + * @param {number} timestamp * @param {string} message * @return {boolean} */ diff --git a/solution/0300-0399/0359.Logger Rate Limiter/README_EN.md b/solution/0300-0399/0359.Logger Rate Limiter/README_EN.md index 2c8b6b0213308..f774c80527ca3 100644 --- a/solution/0300-0399/0359.Logger Rate Limiter/README_EN.md +++ b/solution/0300-0399/0359.Logger Rate Limiter/README_EN.md @@ -65,7 +65,11 @@ logger.shouldPrintMessage(11, "foo"); // 11 >= 11, return true, nex -### Solution 1 +### Solution 1: Hash Table + +We use a hash table $\textit{ts}$ to store the next available print timestamp for each message. When the `shouldPrintMessage` method is called, we check whether the current timestamp is greater than or equal to the next available print timestamp for the message. If so, we update the next available print timestamp to the current timestamp plus 10 and return `true`; otherwise, we return `false`. + +The time complexity is $O(1)$. The space complexity is $O(m)$, where $m$ is the number of distinct messages. @@ -73,22 +77,15 @@ logger.shouldPrintMessage(11, "foo"); // 11 >= 11, return true, nex ```python class Logger: + def __init__(self): - """ - Initialize your data structure here. - """ - self.limiter = {} + self.ts = {} def shouldPrintMessage(self, timestamp: int, message: str) -> bool: - """ - Returns true if the message should be printed in the given timestamp, otherwise returns false. - If this method returns false, the message will not be printed. - The timestamp is in seconds granularity. - """ - t = self.limiter.get(message, 0) + t = self.ts.get(message, 0) if t > timestamp: return False - self.limiter[message] = timestamp + 10 + self.ts[message] = timestamp + 10 return True @@ -101,25 +98,17 @@ class Logger: ```java class Logger { + private Map ts = new HashMap<>(); - private Map limiter; - - /** Initialize your data structure here. */ public Logger() { - limiter = new HashMap<>(); } - /** - Returns true if the message should be printed in the given timestamp, otherwise returns - false. If this method returns false, the message will not be printed. The timestamp is in - seconds granularity. - */ public boolean shouldPrintMessage(int timestamp, String message) { - int t = limiter.getOrDefault(message, 0); - if (t > timestamp) { + int t = ts.getOrDefault(message, 0); + if (timestamp < t) { return false; } - limiter.put(message, timestamp + 10); + ts.put(message, timestamp + 10); return true; } } @@ -131,6 +120,59 @@ class Logger { */ ``` +#### C++ + +```cpp +class Logger { +public: + Logger() { + } + + bool shouldPrintMessage(int timestamp, string message) { + if (ts.contains(message) && ts[message] > timestamp) { + return false; + } + ts[message] = timestamp + 10; + return true; + } + +private: + unordered_map ts; +}; + +/** + * Your Logger object will be instantiated and called as such: + * Logger* obj = new Logger(); + * bool param_1 = obj->shouldPrintMessage(timestamp,message); + */ +``` + +#### Go + +```go +type Logger struct { + ts map[string]int +} + +func Constructor() Logger { + return Logger{ts: make(map[string]int)} +} + +func (this *Logger) ShouldPrintMessage(timestamp int, message string) bool { + if t, ok := this.ts[message]; ok && timestamp < t { + return false + } + this.ts[message] = timestamp + 10 + return true +} + +/** + * Your Logger object will be instantiated and called as such: + * obj := Constructor(); + * param_1 := obj.ShouldPrintMessage(timestamp,message); + */ +``` + #### JavaScript ```js @@ -144,8 +186,8 @@ var Logger = function () { /** * Returns true if the message should be printed in the given timestamp, otherwise returns false. If this method returns false, the message will not be printed. - The timestamp is in seconds granularity. - * @param {number} timestamp + The timestamp is in seconds granularity. + * @param {number} timestamp * @param {string} message * @return {boolean} */ diff --git a/solution/0300-0399/0359.Logger Rate Limiter/Solution.cpp b/solution/0300-0399/0359.Logger Rate Limiter/Solution.cpp new file mode 100644 index 0000000000000..fba8474df099c --- /dev/null +++ b/solution/0300-0399/0359.Logger Rate Limiter/Solution.cpp @@ -0,0 +1,22 @@ +class Logger { +public: + Logger() { + } + + bool shouldPrintMessage(int timestamp, string message) { + if (ts.contains(message) && ts[message] > timestamp) { + return false; + } + ts[message] = timestamp + 10; + return true; + } + +private: + unordered_map ts; +}; + +/** + * Your Logger object will be instantiated and called as such: + * Logger* obj = new Logger(); + * bool param_1 = obj->shouldPrintMessage(timestamp,message); + */ diff --git a/solution/0300-0399/0359.Logger Rate Limiter/Solution.go b/solution/0300-0399/0359.Logger Rate Limiter/Solution.go new file mode 100644 index 0000000000000..e7f3efa8a4deb --- /dev/null +++ b/solution/0300-0399/0359.Logger Rate Limiter/Solution.go @@ -0,0 +1,21 @@ +type Logger struct { + ts map[string]int +} + +func Constructor() Logger { + return Logger{ts: make(map[string]int)} +} + +func (this *Logger) ShouldPrintMessage(timestamp int, message string) bool { + if t, ok := this.ts[message]; ok && timestamp < t { + return false + } + this.ts[message] = timestamp + 10 + return true +} + +/** + * Your Logger object will be instantiated and called as such: + * obj := Constructor(); + * param_1 := obj.ShouldPrintMessage(timestamp,message); + */ diff --git a/solution/0300-0399/0359.Logger Rate Limiter/Solution.java b/solution/0300-0399/0359.Logger Rate Limiter/Solution.java index 556bbad97dbdb..b516b1048c378 100644 --- a/solution/0300-0399/0359.Logger Rate Limiter/Solution.java +++ b/solution/0300-0399/0359.Logger Rate Limiter/Solution.java @@ -1,23 +1,15 @@ class Logger { + private Map ts = new HashMap<>(); - private Map limiter; - - /** Initialize your data structure here. */ public Logger() { - limiter = new HashMap<>(); } - /** - Returns true if the message should be printed in the given timestamp, otherwise returns - false. If this method returns false, the message will not be printed. The timestamp is in - seconds granularity. - */ public boolean shouldPrintMessage(int timestamp, String message) { - int t = limiter.getOrDefault(message, 0); - if (t > timestamp) { + int t = ts.getOrDefault(message, 0); + if (timestamp < t) { return false; } - limiter.put(message, timestamp + 10); + ts.put(message, timestamp + 10); return true; } } @@ -26,4 +18,4 @@ public boolean shouldPrintMessage(int timestamp, String message) { * Your Logger object will be instantiated and called as such: * Logger obj = new Logger(); * boolean param_1 = obj.shouldPrintMessage(timestamp,message); - */ \ No newline at end of file + */ diff --git a/solution/0300-0399/0359.Logger Rate Limiter/Solution.py b/solution/0300-0399/0359.Logger Rate Limiter/Solution.py index 23e2033851c86..65342e6485e99 100644 --- a/solution/0300-0399/0359.Logger Rate Limiter/Solution.py +++ b/solution/0300-0399/0359.Logger Rate Limiter/Solution.py @@ -1,20 +1,13 @@ class Logger: + def __init__(self): - """ - Initialize your data structure here. - """ - self.limiter = {} + self.ts = {} def shouldPrintMessage(self, timestamp: int, message: str) -> bool: - """ - Returns true if the message should be printed in the given timestamp, otherwise returns false. - If this method returns false, the message will not be printed. - The timestamp is in seconds granularity. - """ - t = self.limiter.get(message, 0) + t = self.ts.get(message, 0) if t > timestamp: return False - self.limiter[message] = timestamp + 10 + self.ts[message] = timestamp + 10 return True