Skip to content

Commit 9159b3b

Browse files
committed
✨feat: add 895
1 parent aa26a08 commit 9159b3b

File tree

3 files changed

+142
-0
lines changed

3 files changed

+142
-0
lines changed

Index/哈希表.md

+1
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
| [884. 两句话中的不常见单词](https://leetcode-cn.com/problems/uncommon-words-from-two-sentences/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/uncommon-words-from-two-sentences/solution/gong-shui-san-xie-shu-ju-jie-gou-mo-ni-t-wwam/) | 简单 | 🤩🤩🤩🤩🤩 |
5959
| [888. 公平的糖果棒交换](https://leetcode-cn.com/problems/fair-candy-swap/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/fair-candy-swap/solution/gong-shui-san-xie-yi-ti-shuang-jie-po-su-uant/) | 简单 | 🤩🤩 |
6060
| [890. 查找和替换模式](https://leetcode.cn/problems/find-and-replace-pattern/) | [LeetCode 题解链接](https://leetcode.cn/problems/find-and-replace-pattern/solution/by-ac_oier-s4cw/) | 中等 | 🤩🤩🤩🤩 |
61+
| [895. 最大频率栈](https://leetcode.cn/problems/maximum-frequency-stack/) | [LeetCode 题解链接](https://leetcode.cn/problems/maximum-frequency-stack/solution/by-ac_oier-tquk/) | 困难 | 🤩🤩🤩🤩🤩 |
6162
| [930. 和相同的二元子数组](https://leetcode-cn.com/problems/binary-subarrays-with-sum/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/binary-subarrays-with-sum/solution/gong-shui-san-xie-yi-ti-shuang-jie-qian-hfoc0/) | 中等 | 🤩🤩🤩 |
6263
| [954. 二倍数对数组](https://leetcode-cn.com/problems/array-of-doubled-pairs/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/array-of-doubled-pairs/solution/by-ac_oier-d1z7/) | 中等 | 🤩🤩🤩 |
6364
| [961. 在长度 2N 的数组中找出重复 N 次的元素](https://leetcode.cn/problems/n-repeated-element-in-size-2n-array/) | [LeetCode 题解链接](https://leetcode.cn/problems/n-repeated-element-in-size-2n-array/solution/by-ac_oier-bslq/) | 简单 | 🤩🤩🤩🤩 |

Index/模拟.md

+1
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@
126126
| [883. 三维形体投影面积](https://leetcode-cn.com/problems/projection-area-of-3d-shapes/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/projection-area-of-3d-shapes/solution/by-ac_oier-r6hj/) | 简单 | 🤩🤩🤩🤩 |
127127
| [884. 两句话中的不常见单词](https://leetcode-cn.com/problems/uncommon-words-from-two-sentences/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/uncommon-words-from-two-sentences/solution/gong-shui-san-xie-shu-ju-jie-gou-mo-ni-t-wwam/) | 简单 | 🤩🤩🤩🤩 |
128128
| [890. 查找和替换模式](https://leetcode.cn/problems/find-and-replace-pattern/) | [LeetCode 题解链接](https://leetcode.cn/problems/find-and-replace-pattern/solution/by-ac_oier-s4cw/) | 中等 | 🤩🤩🤩🤩 |
129+
| [895. 最大频率栈](https://leetcode.cn/problems/maximum-frequency-stack/) | [LeetCode 题解链接](https://leetcode.cn/problems/maximum-frequency-stack/solution/by-ac_oier-tquk/) | 困难 | 🤩🤩🤩🤩🤩 |
129130
| [896. 单调数列](https://leetcode-cn.com/problems/monotonic-array/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/monotonic-array/solution/wei-shi-yao-yi-ci-bian-li-yao-bi-liang-c-uglp/) | 简单 | 🤩🤩🤩🤩 |
130131
| [905. 按奇偶排序数组](https://leetcode-cn.com/problems/sort-array-by-parity/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/sort-array-by-parity/solution/by-ac_oier-nuz7/) | 简单 | 🤩🤩🤩 |
131132
| [915. 分割数组](https://leetcode.cn/problems/partition-array-into-disjoint-intervals/) | [LeetCode 题解链接](https://leetcode.cn/problems/partition-array-into-disjoint-intervals/solution/by-ac_oier-yyen/) | 中等 | 🤩🤩🤩🤩 |
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
### 题目描述
2+
3+
这是 LeetCode 上的 **[895. 最大频率栈](https://leetcode.cn/problems/maximum-frequency-stack/solution/by-ac_oier-tquk/)** ,难度为 **困难**
4+
5+
Tag : 「哈希表」、「模拟」
6+
7+
8+
9+
设计一个类似堆栈的数据结构,将元素推入堆栈,并从堆栈中弹出出现频率最高的元素。
10+
11+
实现 `FreqStack` 类:
12+
* `FreqStack()` 构造一个空的堆栈。
13+
* `void push(int val)` 将一个整数 `val` 压入栈顶。
14+
* `int pop()` 删除并返回堆栈中出现频率最高的元素。
15+
16+
如果出现频率最高的元素不只一个,则移除并返回最接近栈顶的元素。
17+
18+
示例 1:
19+
```
20+
输入:
21+
["FreqStack","push","push","push","push","push","push","pop","pop","pop","pop"],
22+
[[],[5],[7],[5],[7],[4],[5],[],[],[],[]]
23+
24+
输出:[null,null,null,null,null,null,null,5,7,5,4]
25+
26+
解释:
27+
FreqStack = new FreqStack();
28+
freqStack.push (5);//堆栈为 [5]
29+
freqStack.push (7);//堆栈是 [5,7]
30+
freqStack.push (5);//堆栈是 [5,7,5]
31+
freqStack.push (7);//堆栈是 [5,7,5,7]
32+
freqStack.push (4);//堆栈是 [5,7,5,7,4]
33+
freqStack.push (5);//堆栈是 [5,7,5,7,4,5]
34+
freqStack.pop ();//返回 5 ,因为 5 出现频率最高。堆栈变成 [5,7,5,7,4]。
35+
freqStack.pop ();//返回 7 ,因为 5 和 7 出现频率最高,但7最接近顶部。堆栈变成 [5,7,5,4]。
36+
freqStack.pop ();//返回 5 ,因为 5 出现频率最高。堆栈变成 [5,7,4]。
37+
freqStack.pop ();//返回 4 ,因为 4, 5 和 7 出现频率最高,但 4 是最接近顶部的。堆栈变成 [5,7]。
38+
```
39+
40+
提示:
41+
* $0 <= val <= 10^9$
42+
* `push` 和 `pop` 的操作数不大于 $2 \times 10^4$
43+
* 输入保证在调用 `pop` 之前堆栈中至少有一个元素
44+
45+
---
46+
47+
### 哈希表
48+
49+
这是一道很纯的哈希表题儿。
50+
51+
首先,我们容易想到建立 **第一个哈希表 `cnts` 用于记录某个数值的出现次数,`cnts[val] = c` 含义为数值 `val` 当前在栈中的出现次数为 `c`。我们称该哈希表为「计数哈希表」**
52+
53+
再结合每次 `pop` 需要返回「频率最大的元素,若有多个则返回最考虑栈顶的一个」的要求,我们还可以 **建立第二个哈希 `map`,该哈希表以「出现次数 `c`」为键,以「出现次数均为 `c` 的元素序列」为值,`map[c] = A = [...]` 含义为出现次数为 `c` 的序列为 `A`,并且序列 `A` 中的结尾元素为出现次数为 `c` 的所有元素中最靠近栈顶的元素。我们称该哈希表为「分桶哈希表」**
54+
55+
最后再额外使用一个变量 `max` 记录当前最大出现频数,不难发现,`max` 必然是以步长 $\pm 1$ 进行变化(当出现次数为 `max` 的元素被 `pop` 掉了一个后,必然剩下 `max - 1` 个),因此当我们在某次 `pop` 操作后发现出现次数为 `max` 的集合为空时,对 `max` 进行自减操作即可。
56+
57+
将题目给的样例作为 🌰 ,大家可以看看 `cnts``map``max` 三者如何变化,以及 `pop` 的更新逻辑:
58+
59+
![image.png](https://pic.leetcode.cn/1669771856-XhpLSw-image.png)
60+
61+
Java 代码:
62+
```Java
63+
class FreqStack {
64+
Map<Integer, List<Integer>> map = new HashMap<>();
65+
Map<Integer, Integer> cnts = new HashMap<>();
66+
int max;
67+
public void push(int val) {
68+
cnts.put(val, cnts.getOrDefault(val, 0) + 1);
69+
int c = cnts.get(val);
70+
List<Integer> list = map.getOrDefault(c, new ArrayList<>());
71+
list.add(val);
72+
map.put(c, list);
73+
max = Math.max(max, c);
74+
}
75+
public int pop() {
76+
List<Integer> list = map.get(max);
77+
int ans = list.remove(list.size() - 1);
78+
cnts.put(ans, cnts.get(ans) - 1);
79+
if (list.size() == 0) max--;
80+
return ans;
81+
}
82+
}
83+
```
84+
TypeScript 代码:
85+
```TypeScript
86+
class FreqStack {
87+
map: Map<number, Array<number>> = new Map<number, Array<number>>()
88+
cnst: Map<number, number> = new Map<number, number>()
89+
max: number = 0
90+
push(val: number): void {
91+
if (!this.cnst.has(val)) this.cnst.set(val, 0)
92+
this.cnst.set(val, this.cnst.get(val) + 1)
93+
const c = this.cnst.get(val)
94+
if (!this.map.has(c)) this.map.set(c, new Array<number>())
95+
this.map.get(c).push(val)
96+
this.max = Math.max(this.max, c)
97+
}
98+
pop(): number {
99+
const ans = this.map.get(this.max).pop()
100+
if (this.map.get(this.max).length == 0) this.max--
101+
this.cnst.set(ans, this.cnst.get(ans) - 1)
102+
return ans
103+
}
104+
}
105+
```
106+
Python 代码:
107+
```Python
108+
class FreqStack:
109+
def __init__(self):
110+
self.cnts = defaultdict(int)
111+
self.map = defaultdict(list)
112+
self.mv = 0
113+
114+
def push(self, val: int) -> None:
115+
self.cnts[val] += 1
116+
c = self.cnts[val]
117+
self.map[c].append(val)
118+
self.mv = max(self.mv, c)
119+
120+
def pop(self) -> int:
121+
ans = self.map[self.mv].pop()
122+
self.cnts[ans] -= 1
123+
self.mv -= 0 if self.map[self.mv] else 1
124+
return ans
125+
```
126+
* 时间复杂度:所有操作均为 $O(1)$
127+
* 空间复杂度:所有入栈的节点最多会被存储两次,一次在计数哈希表中,一次在分桶哈希表中,复杂度为 $O(n)$
128+
129+
---
130+
131+
### 最后
132+
133+
这是我们「刷穿 LeetCode」系列文章的第 `No.895` 篇,系列开始于 2021/01/01,截止于起始日 LeetCode 上共有 1916 道题目,部分是有锁题,我们将先把所有不带锁的题目刷完。
134+
135+
在这个系列文章里面,除了讲解解题思路以外,还会尽可能给出最为简洁的代码。如果涉及通解还会相应的代码模板。
136+
137+
为了方便各位同学能够电脑上进行调试和提交代码,我建立了相关的仓库:https://github.com/SharingSource/LogicStack-LeetCode
138+
139+
在仓库地址里,你可以看到系列文章的题解链接、系列文章的相应代码、LeetCode 原题链接和其他优选题解。
140+

0 commit comments

Comments
 (0)