专题:栈和队列
题目:滑动窗口最大值
给定一个数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。
返回滑动窗口中的最大值。
题目解析:怎么处理它?我们实现一个单调队列,(也是一个宫殿)。然后一个数组里面有很多的元素要依次进入队列,(其他地方的人想要进入这个宫殿),遍历数组元素进入单调队列中,(那些人进入宫殿),进入队列时,如果单调队列为空,或者队尾的元素大于要插入的元素,那么直接元素尾插入队列。(如果当前要进宫殿的人发现,宫殿里面没有人,或者前面有人了,但是都比自己厉害,那么它就进入宫殿要么当老大,要么很低调的,夹尾巴跟在比她厉害的人后面!)。如果队列不为空,并且队尾的元素 小于当前要插入的元素,那么就要把队尾的元素弹出,然后再比较,小于当前元素的话再弹出.....直到队列为空,自己当队首,或者遇到了比自己大的队尾元素,就插入队尾。(这个人如果发现宫殿里面有人,但是那些比自己来的早的人,都比自己弱,他就会把他们一个一个的杀掉,直到杀光自己当老大,或者遇到了一个比自己厉害的人,那么就老老实实跟在人家后面,夹着尾巴做人。)队列的出队列操作,因为我们要求窗口大小K,而且窗口会一个一个完后走。所以遍历操作的时候,我们每次都执行一次,队列弹出操作。防止队列里面排序的元素多余K个。如果当前要过去的元素(窗口的第一个元素)是最大值,那么就把它执行弹出操作,如果当前要过去的元素不是最大值,那么它在其他元素进队列的时候,已经pop 了,所以不用再次对他进程pop操作。(历史的长河在滚动,每个国王的最长的寿命是K年,K年之内 它要接受来自新人的挑战,如果还没被新来的人杀掉的话,那么他就会老死,然后被弹出。新来的人里面会出现一个王。如果现在要老死的元素不是国王,是其他人,那么其实这个人在其他人进帝国的时候,已经把它杀了,所以不用再次让他老死。)而我们用数组去记录每个K窗口里面的最大值,就是相当于我们在记录每个时期的王的姓名。
代码实现:
有趣的故事:单调队列真是一种让人感到五味杂陈的数据结构,它的维护过程更是如此.....就拿此题来说,队头最大,往队尾方向单调......有机会站在队头的老大永远心狠手辣,当它从队尾杀进去的时候,如果它发现这里面没一个够自己打的,它会毫无人性地屠城,把原先队里的人头全部丢出去,转身建立起自己的政权,野心勃勃地准备开创一个新的王朝.....这时候,它的人格竟发生了一百八十度大反转,它变成了一位胸怀宽广的慈父!它热情地请那些新来的“小个子”们入住自己的王国......然而,这些小个子似乎天性都是一样的——嫉妒心强,倘若见到比自己还小的居然更早入住王国,它们会心狠手辣地找一个夜晚把它们通通干掉,好让自己享受更大的“蛋糕”;当然,遇到比自己强大的,它们也没辙,乖乖夹起尾巴做人。像这样的暗杀事件每天都在上演,虽然王国里日益笼罩上白色恐怖,但是好在没有后来者强大到足以干翻国王,江山还算能稳住。直到有一天,闯进来了一位真正厉害的角色,就像当年打江山的国王一样,手段狠辣,野心膨胀,于是又是大屠城......历史总是轮回的。
附加:个人感觉,窗口的移动可以理解为“岁月的流逝”,即便再厉害的“国王”寿元也是有限的,这个曾经“屠城”的国王一方面在其有限的“一生”中,要面对新加入的元素的挑战(push 操作),另一方面在“时间”的面前,即便他再强大也是会消失在历史的长河中(窗口的移动)
附加:所以历代国王都被载入史册,这就是我们要寻找的。 (用数组记录每个时期的最大值)
自己的理解:单调队列的核心,只保存有可能成为最大值的元素。新进入的元素,在它进入队列的那一瞬间,就已经把不如它的全部杀了。然后我们弹出的还是,是每次判断,当前弹出的这个元素是不是这个时期的王,如果是说明这个王的时间到了,它老死了。被弹出。如果不是这个时期的王,那么说明这个元素在插入的时候已经被处理了,现在不用再进行pop操作。
题目二:前 K 个高频元素
给定一个非空的整数数组,返回其中出现频率前 k 高的元素。
示例 1:
- 输入: nums = [1,1,1,2,2,3], k = 2
- 输出: [1,2]
示例 2:
- 输入: nums = [1], k = 1
- 输出: [1]
题目解析:
遍历数组,使用map把每个元素的 数值信息 和 次数信息 保存进去。构建小顶堆,根据map元素<key,对应出现次数> 的第二个参数,用它插入到小顶堆里面,小顶堆里面最多保存K个元素,一大多于K个就要进行弹出。直到遍历完map,得到的小顶堆里面的元素,就是数组中出现次数最多的K个元素,但是因为小顶堆,先出来的是小元素,所以要按从后到前的顺序,出元素。
具体细节:map的使用方式 ;遍历数组,拿到数组元素充当map元素的下标map[nums[i] ]++;
优先级队列的使用方式;priority_queue<元素类型,底层容器,比较方式> pri_que;
我们可以用优先级队列保存各种元素,按照大根堆 和 小根堆 的方式。
赋值运算符重载的方式; 由于我们优先级队列里面使用的元素类型是map类型,所以我们需要重载比较函数。
代码实现: