力扣第895题
实现 FreqStack,模拟类似栈的数据结构的操作的一个类。
FreqStack 有两个函数:
push(int x),将整数 x 推入栈中。 pop(),它移除并返回栈中出现最频繁的元素。
如果最频繁的元素不只一个,则移除并返回最接近栈顶的元素。示例:
输入:
[“FreqStack”,“push”,“push”,“push”,“push”,“push”,“push”,“pop”,“pop”,“pop”,“pop”],
[[],[5],[7],[5],[7],[4],[5],[],[],[],[]]
输出:[null,null,null,null,null,null,null,5,7,5,4] 解释: 执行六次 .push
操作后,栈自底向上为 [5,7,5,7,4,5]。然后:pop() -> 返回 5,因为 5 是出现频率最高的。 栈变成 [5,7,5,7,4]。
pop() -> 返回 7,因为 5 和 7 都是频率最高的,但 7 最接近栈顶。 栈变成 [5,7,5,4]。
pop() -> 返回 5 。 栈变成 [5,7,4]。
pop() -> 返回 4 。 栈变成 [5,7]。
提示:
对 FreqStack.push(int x) 的调用中 0 <= x <= 10^9。 如果栈的元素数目为零,则保证不会调用
FreqStack.pop()。 单个测试样例中,对 FreqStack.push 的总调用次数不会超过 10000。 单个测试样例中,对
FreqStack.pop 的总调用次数不会超过 10000。 所有测试样例中,对 FreqStack.push 和
FreqStack.pop 的总调用次数不会超过 150000。来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/maximum-frequency-stack
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
简而言之, 一直往该数据结构里面push整数, 和往外pop. pop的时候要把push次数最多,同样多就是最后push那个数字弹出.
那么用一个键值对数组来存储数据是不错的选择.出现次数为键, 出现相同次数的数字组成一个数组作为值
譬如按顺序push 1 2 3 3 2 3 3 1 1
初始数组values = [];
push(1);
$values = [
1=>[1]
];
push(2);
$values = [
1=>[1,2]
];
push(3);
$values = [
1=>[1,2,3]
];
push(3);
$values = [
1=>[1,2,3],
2=>[3]
];
push(2);
$values = [
1=>[1,2,3],
2=>[3,2]
];
push(3);
$values = [
1=>[1,2,3],
2=>[3,2],
3=>[3]
];
push(3);
$values = [
1=>[1,2,3],
2=>[3,2],
3=>[3],
4=>[3]
];
push(1);
$values = [
1=>[1,2,3],
2=>[3,2,1],
3=>[3],
4=>[3]
];
push(1);
$values = [
1=>[1,2,3],
2=>[3,2,1],
3=>[3,1],
4=>[3]
];
像这样的就很容易知道弹出顺序应该是 3 1 3 1 2 3 3 2 1
但是再一次push(1)的时候, 怎么知道应当把它存入到键为3的数组下面呢?
方案一:
从第一个开始遍历, 如果当前出现次数下的数组没有1则在当前出现次数下加入该数字并返回,否则去判断下一个.不占用额外空间,但时间复杂度较高
定义私有变量$values
private $values = [];
那么push方法如下
function push($x) {
$time = 1;
foreach ($this->values as $time=>$value) {
if (!isset($value[$x])){
$time--;
break;
}
}
$this->values[++$time] [$x]= $x;
return null;
}
pop方法如下
function pop() {
end($this->values);
$time = key($this->values);
$int = array_pop($this->values[$time]);
if (!$this->values[$time]){
array_pop($this->values);
}
return $int;
}
运行结果如下: 用时1912ms, 内存30.6MB
方案二:
为了更容易找到当前数字N出现到第几次了,再加一个数组来存储每个数字的出现次数
$times = [
1=>3,
2=>2,
3=>4
]
这样子在再次推入1的时候就很容易知道应该把它加入到下标为4的数组下面了. 在push和pop操作的时候要维护$values和$times两个数组. 占用额外空间但时间复杂度较低
定义私有变量
private $values = [];
private $times = [];
push方法如下:
function push($x) {
if (isset($this->times[$x])){
$this->times[$x]++;
}else{
$this->times[$x] = 1;
}
$this->values[$this->times[$x]] [$x] = $x;
return null;
}
pop方法如下:
function pop() {
end($this->values);
$time = key($this->values);
$int = array_pop($this->values[$time]);
if (!$this->values[$time]){
array_pop($this->values);
}
$this->times[$int]--;
return $int;
}
运行结果如下: 用时228ms, 内存31.3MB
显然方案二多消耗一点点内存, 大大缩减了执行用时