栈和队列
基本性质
栈
- 先进后出
- 实现方式:有数组和链表两种形式。数组实现较容易,链表实现较复杂。
- 基本操作:top / pop / push / size 操作,时间复杂度 O(1)
- 深度优先(DFS)使用栈实现
队列
- 先进先出
- 实现方式:有数组和链表两种形式。数组实现较容易,链表实现较复杂。
- 基本操作:top / pop / push / size 操作,时间复杂度 O(1)
- 宽度优先(BFS)使用队列实现
双端队列
- 首尾均可以压入和弹出元素
优先级队列
- 根据元素的优先级,决定元素的弹出顺序
- 堆结构
经典题目
- 最小栈
思路:辅助栈。
lc 155 https://leetcode.cn/problems/min-stack/ - 基于栈实现队列
思路:两个栈,一个负责压入栈,一个负责弹出栈。
https://leetcode.cn/problems/yong-liang-ge-zhan-shi-xian-dui-lie-lcof/ - 实现栈的逆序,只能用递归操作和栈本身的函数实现。不能使用其它数据结构。
思路:利用递归函数的函数栈。
牛客:https://www.nowcoder.com/practice/1de82c89cc0e43e9aa6ee8243f4dbefd?tpId=101&rp=1&ru=%2Fexam%2Foj%2Fta&qru=%2Fexam%2Foj%2Fta&sourceUrl=%2Fexam%2Foj%2Fta%3Fpage%3D1%26pageSize%3D50%26search%3Dkmp%26tpId%3D101%26type%3D101&difficulty=&judgeStatus=&tags=&title=%E6%A0%88&gioEnter=menu - 将栈中从顶到底按照从大到小排序,只许申请一个栈,除此之外可以申请新的变量,但不能申请额外的数据结构。
思路:汉诺塔原理
https://leetcode.cn/problems/sort-of-stacks-lcci/
https://www.nowcoder.com/practice/ff8cba64e7894c5582deafa54cca8ff2?tpId=101&rp=1&ru=%2Fexam%2Foj%2Fta&qru=%2Fexam%2Foj%2Fta&sourceUrl=%2Fexam%2Foj%2Fta%3Fpage%3D1%26pageSize%3D50%26search%3Dkmp%26tpId%3D101%26type%3D101&difficulty=&judgeStatus=&tags=&title=%E6%A0%88&gioEnter=menu - 滑动窗口的最大值
思路:双端队列
https://leetcode.cn/problems/hua-dong-chuang-kou-de-zui-da-zhi-lcof/ - 给定一个没有重复元素的数组arr,写出生成这个数组maxTree的函数。要求如果数组长度为N,时间复杂度为O(N),额外空间复杂度为O(N)。
maxTree是一个二叉树,数组的每一个值对应二叉树的一个节点。
包括maxTree树在内,且在其中的每一棵子树上,值最大的节点都是树的头。
https://leetcode.cn/problems/maximum-binary-tree/
链表
链表:
- 算法实现上难度较低,主要是考察代码实现的能力
- 链表的存储空间是临时分配的,不保证空间上的连续性。
- 链表的分类
- 从连接方向上:单链表、双链表
- 按照有环、无环分类:普通链表、循环链表
- 链表插入、链表删除、链表翻转
- 单链表,反转链表
https://leetcode.cn/problems/reverse-linked-list/
def reverseList(self, head: ListNode) -> ListNode:
# 链表为空时直接返回
if not head:
return None
# 链表不为空时,逐个反转
prev = None
cur = head
while cur:
nextPtr = cur.next
cur.next = prev
prev = cur
cur = nextPtr
return prev
- 向有序的环形链表中插入节点
https://leetcode.cn/problems/insert-into-a-sorted-circular-linked-list/
"""注意边界条件!!!!"""
def insert(self, head, insertVal):
"""
:type head: Node
:type insertVal: int
:rtype: Node
"""
node = Node(insertVal)
if not head:
node.next = node
return node
else:
pre = head
cur = head.next
# 首先找到head节点
while cur != head and pre!=cur and pre.val <= cur.val:
pre = cur
cur = cur.next
newHead = cur
# 从新head开始往后找insert的位置
pre = newHead
cur = newHead.next
while cur != newHead and pre != cur and pre.val <= cur.val:
if pre.val <= insertVal and insertVal <= cur.val:
# 插入insertVal
pre.next = node
node.next = cur
return head
pre = cur
cur = cur.next
# 到达循环链表的尾部-头部交界处
pre.next = node
node.next = cur
return head
- 给定单链表中节点node,但是不给头节点head,如何删除node节点?时间复杂度O(1)。
作为面试题简单,但在工程实践中存在问题。
https://leetcode.cn/problems/delete-node-in-a-linked-list/
def deleteNode(self, node):
# 伪删除node点
node.val = node.next.val
# 删除node的下一个节点
node.next = node.next.next
- 给定一个链表,再给定一个整数 pivot,请将链表调整为左部分都是值小于 pivot 的节点,中间部分都是值等于 pivot 的节点, 右边部分都是大于 pivot 的节点。
分成三个小链表,再拼起来。
https://www.nowcoder.com/practice/04fcabc5d76e428c8100dbd855761778?tpId=101&tqId=33181&rp=1&ru=/exam/oj/ta&qru=/exam/oj/ta&sourceUrl=%2Fexam%2Foj%2Fta%3Fpage%3D1%26pageSize%3D50%26search%3D%25E9%2593%25BE%25E8%25A1%25A8%26tpId%3D101%26type%3D101&difficulty=undefined&judgeStatus=undefined&tags=&title=%E9%93%BE%E8%A1%A8 - 给定两个有序链表的头节点,打印两个链表公共部分
https://www.nowcoder.com/practice/8943eea40dbb4185b187d80fd050fee9?tpId=101&tqId=33116&rp=1&ru=/exam/oj/ta&qru=/exam/oj/ta&sourceUrl=%2Fexam%2Foj%2Fta%3Fpage%3D1%26pageSize%3D50%26search%3D%25E9%2593%25BE%25E8%25A1%25A8%26tpId%3D101%26type%3D101&difficulty=undefined&judgeStatus=undefined&tags=&title=%E9%93%BE%E8%A1%A8 - 每K个节点之间逆序,最后不够K个节点一组,不调整最后几个节点。
https://leetcode.cn/problems/reverse-nodes-in-k-group/
def reverseKGroup(self, head, k):
k_cnt = 0
prev = None
cur = head
k_nextP = head
nextP = None
orig_head = head
# 构建首组反转链表
while k_nextP:
if k_cnt < k:
k_nextP = k_nextP.next
k_cnt += 1
if k_cnt == k: #此时k_nextP在下一组的第一个位置
prev = k_nextP
while cur and cur != k_nextP:
nextP = cur.next
cur.next = prev
prev = cur
cur = nextP
break
if k_cnt < k: #首次未进入反转循环
return head
elif k_cnt == k and not k_nextP: #首次正好满足一次循环
return prev
else:
init_head = prev
k_cnt = 0
while k_nextP:
if k_cnt < k:
k_nextP = k_nextP.next
k_cnt += 1
if k_cnt == k: #此时k_nextP在下一组的第一个位置
prev = k_nextP
while cur and cur != k_nextP:
nextP = cur.next
cur.next = prev
prev = cur
cur = nextP
tmp = orig_head.next
orig_head.next = prev
orig_head = tmp
k_cnt = 0
return init_head
https://www.nowcoder.com/practice/66285653d28b4ed6a15613477670e936?tpId=101&tqId=33187&rp=1&ru=/exam/oj/ta&qru=/exam/oj/ta&sourceUrl=%2Fexam%2Foj%2Fta%3Fpage%3D1%26pageSize%3D50%26search%3D%25E9%2593%25BE%25E8%25A1%25A8%26tpId%3D101%26type%3D101&difficulty=undefined&judgeStatus=undefined&tags=&title=%E9%93%BE%E8%A1%A8
8. 给定一个单链表的头节点,再给定一个整数value,将链表中所有等于value的节点删掉。
https://www.nowcoder.com/practice/1a5fd679e31f4145a10d46bb8fd3d211?tpId=101&tqId=33206&rp=1&ru=/exam/oj/ta&qru=/exam/oj/ta&sourceUrl=%2Fexam%2Foj%2Fta%3Fpage%3D1%26pageSize%3D50%26search%3D%25E9%2593%25BE%25E8%25A1%25A8%26tpId%3D101%26type%3D101&difficulty=undefined&judgeStatus=undefined&tags=&title=%E9%93%BE%E8%A1%A8
9. 判断链表是否为回文结构。
https://www.nowcoder.com/practice/4b13dff86de64f84ac284e31067b86e2?tpId=101&tqId=33179&rp=1&ru=/exam/oj/ta&qru=/exam/oj/ta&sourceUrl=%2Fexam%2Foj%2Fta%3Fpage%3D1%26pageSize%3D50%26search%3D%25E9%2593%25BE%25E8%25A1%25A8%26tpId%3D101%26type%3D101&difficulty=undefined&judgeStatus=undefined&tags=&title=%E9%93%BE%E8%A1%A8
申请辅助栈
判断链表是否有环,并返回入环的第一个节点?
如何判断两个无环链表是否相交?相交的话,返回第一个相交的节点?
如何判断两个有环链表是否相交?相交的话,返回第一个相交的节点?
如何判断两个单链表是否相交?相交的话,返回第一个相交的节点?
一个链表中,不仅有next还有rand,复制这种含有rand结构的链表。