栈与队列
队列:
队列是典型的 FIFO 数据结构。插入(insert)操作也称作入队(enqueue),新元素始终被添加在队列的末尾。 删除(delete)操作也被称为出队(dequeue)。 你只能移除第一个元素。
下面是使用内置队列库及其常见操作的一些示例:
// "static void main" must be defined in a public class.
public class Main {
public static void main(String[] args) {
// 1. Initialize a queue.
//初始化一个队列
Queue<Integer> q = new LinkedList();
// 2. Get the first element - return null if queue is empty.
//得到第一个元素,如果队列为空则返回null
System.out.println("The first element is: " + q.peek());
// 3. Push new element.
//入队
q.offer(5);
q.offer(13);
// 4. Pop an element.
//出队
q.poll();
// 5. Get the first element.
//得到第一个元素
System.out.println("The first element is: " + q.peek());
// 7. Get the size of the queue.
//得到队列长度
System.out.println("The size is: " + q.size());
}
}
广度优先搜索(BFS)
广度优先搜索的一个常见应用是找出从根结点到目标结点的最短路径
BFS 的两个主要方案:遍历或找出最短路径
模板一
/**
* Return the length of the shortest path between root and target node.
*/
int BFS(Node root, Node target) {
// store all nodes which are waiting to be processed
//存储所有等待被操作的节点
Queue<Node> queue;
// number of steps neeeded from root to current node
//记录从根到当前节点的步数
int step = 0;
// initialize
//初始化
add root to queue;//将根加入队列中
// BFS广度优先搜索
while (queue is not empty) {//队列不为空
step = step + 1;
// iterate the nodes which are already in the queue
//迭代遍历已经在队列中的节点
int size = queue.size();
for (int i = 0; i < size; ++i) {
Node cur = the first node in queue;//让cur指向当前队列中的第一个节点
return step if cur is target;//如果cur指向的是目标节点,则返回步数
for (Node next : the neighbors of cur) {//遍历cur的所有邻居
add next to queue;//将邻居添加到队列中
}
remove the first node from queue;//将第一个节点从队列中移除
}
}
// there is no path from root to target
//如果没有从根节点到目标节点的路径则返回-1
return -1;
}
模板二
有时,确保我们永远不会访问一个结点两次很重要。否则,我们可能陷入无限循环。如果是这样,我们可以在上面的代码中添加一个哈希集来解决这个问题。这是修改后的伪代码:
/**
* Return the length of the shortest path between root and target node.
*/
int BFS(Node root, Node target) {
// store all nodes which are waiting to be processed
//存储所有等待被操作的节点
Queue<Node> queue;
// store all the used nodes
//存储所有用过的节点
Set<Node> used;
// number of steps neeeded from root to current node
//从根节点到当前节点所需要的步数
int step = 0;
// initialize
//初始化
add root to queue;//将根节点添加到队列中
add root to used;//将根节点添加到hash数组中
// BFS
while (queue is not empty) {
step = step + 1;
// iterate the nodes which are already in the queue
//迭代遍历已经在队列中的节点
int size = queue.size();
for (int i = 0; i < size; ++i) {
Node cur = the first node in queue;
return step if cur is target;
for (Node next : the neighbors of cur) {
if (next is not in used) {//如果邻居不存在于hash数组中,即未被使用过
add next to queue;
add next to used;
}
}
remove the first node from queue;
}
}
return -1; // there is no path from root to target
}
例题
LeetCode200 岛屿数量(Java)
LeetCode752. 打开转盘锁(Java)
LeetCode 365. 水壶问题(Java)
LeetCode 279. 完全平方数(Java)
LeetCode 1162. 地图分析(Java)
栈
后入先出的数据结构。
栈是一个 LIFO 数据结构。通常,插入操作在栈中被称作入栈 push 。与队列类似,总是在堆栈的末尾添加一个新元素。但是,删除操作,退栈 pop ,将始终删除队列中相对于它的最后一个元素。
参考的代码示例:
// "static void main" must be defined in a public class.
public class Main {
public static void main(String[] args) {
// 1. Initialize a stack.
//初始化一个栈
Stack<Integer> s = new Stack<>();
// 2. Push new element.
//入栈
s.push(5);
s.push(13);
s.push(8);
s.push(6);
// 3. Check if stack is empty.
//判断栈是否为空
if (s.empty() == true) {
System.out.println("Stack is empty!");
return;
}
// 4. Pop an element.
//出栈
s.pop();
// 5. Get the top element.
//得到栈顶元素
System.out.println("The top element is: " + s.peek());
// 6. Get the size of the stack.
//得到栈的大小
System.out.println("The size is: " + s.size());
}
}
例题:
LeetCode 155. 最小栈(Java)
LeetCode 20. 有效的括号(Java)
LeetCode 739. 每日温度(Java)
LeetCode 150. 逆波兰表达式求值(Java)
深度优先搜索(DFS)
与 BFS 类似,深度优先搜索(DFS)也可用于查找从根结点到目标结点的路径。
DFS 的递归模板
/*
* Return true if there is a path from cur to target.
*/
boolean DFS(Node cur, Node target, Set<Node> visited) {
return true if cur is target;
for (next : each neighbor of cur) {
if (next is not in visited) {
add next to visted;
return true if DFS(next, target, visited) == true;
}
}
return false;
}
例题:
LeetCode200 岛屿数量(Java)
LeetCode 133. 克隆图(Java)
LeetCode 494. 目标和(Java)
使用显式栈的模板:
/*
* Return true if there is a path from cur to target.
*/
boolean DFS(int root, int target) {
Set<Node> visited;
Stack<Node> s;
add root to s;
while (s is not empty) {
Node cur = the top element in s;
return true if cur is target;
for (Node next : the neighbors of cur) {
if (next is not in visited) {
add next to s;
add next to visited;
}
}
remove cur from s;
}
return false;
}
例题:
LeetCode 94. 二叉树的中序遍历(Java)
总结习题:
LeetCode 232. 用栈实现队列(Java)
LeetCode 225. 用队列实现栈(Java)
LeetCode 394. 字符串解码(Java)
LeetCode 733. 图像渲染(Java)
LeetCode 542. 01 矩阵(Java)
LeetCode 841. 钥匙和房间(Java)