队列代码实现:
package dc;
import java.util.List;
import java.util.ArrayList;
/**
* @author 404小恐龙
* @version 1.8
* @date 2021/10/2 09:42
*/
public class d11{
public static void main(String[] args) {
MyQueue q = new MyQueue();
q.enQueue(5);
q.enQueue(3);
if (q.isEmpty() == false) {
System.out.println(q.Front());
}
q.deQueue();
if (q.isEmpty() == false) {
System.out.println(q.Front());
}
q.deQueue();
if (q.isEmpty() == false) {
System.out.println(q.Front());
}
}
}
class MyQueue {
// store elements
private List<Integer> data;
// 指针指向队列的头部
private int p_start;
public MyQueue() {
data = new ArrayList<Integer>();
p_start = 0;
}
/**
* 元素入队
* @param x 入队元素
* @return 操作成功
*/
public boolean enQueue(int x) {
data.add(x);
return true;
}
/**
* 元素出队
* @return 出队是否成功
*/
public boolean deQueue() {
if (isEmpty() == true) {
return false;
}
/*
队头指针指向下一个元素的索引
*/
p_start++;
return true;
}
/**
* 获取队头元素
* @return 队头元素
*/
public int Front() {
return data.get(p_start);
}
/**
* 队列是否为空
* @return boolean 是否为空
*/
public boolean isEmpty() {
return p_start >= data.size();
}
}
/*
上面的实现很简单,但在某些情况下效率很低。
随着起始指针的移动,浪费了越来越多的空间。
当我们有空间限制时,这将是难以接受的。
这里给出了解决此类问题的方案:
https://leetcode-cn.com/leetbook/read/queue-stack/kgtj7/
动态数组+头部指针 实现的队列,在出队入队操作中,无法重复利用出队释放的空间,所以会浪费空间。
固定数组+头尾双指针 实现循环队列,可以重复利用出队释放的空间,解决空间浪费的问题
问题:如果固定数组满了之后,我还需要入队,而不是让其他出队,这是不是他的弊端,这种情况应该怎么做呢
回答:这个时候可以考虑扩容机制
*/
循环队列代码实现:
/**
* @author 404小恐龙
* @version 1.8
* @date 2021/10/2 09:56
*/
class MyCircularQueue {
private int[] mContainer;
private int mContainerSize;
private int mHead;
private int mTail;
public MyCircularQueue(int k) {
mContainerSize = k;
mContainer = new int[k];
mHead = -1;
mTail = -1;
}
/**
* 元素入队
* @param value 入队元素
* @return 入队是否成功
*/
public boolean enQueue(int value) {
if(isFull()) {
return false;
}
if(isEmpty()) {
mHead ++;
mTail ++;
mContainer[mTail] = value;
return true;
}
mTail ++;
if(mTail > mContainerSize-1) {
/*
尾指针拐回来
*/
mTail = mTail-mContainerSize;
}
mContainer[mTail] = value;
return true;
}
/**
* 元素出队
* @return 出队是否成功
*/
public boolean deQueue() {
if(isEmpty()) {
return false;
}
/*
这种情况下
循环数组中还剩最后一个元素
进入该条件语句
返回true
就不会执行下面的语句了
*/
if(mHead == mTail) {
mHead = -1;
mTail = -1;
return true;
}
mHead ++;
if(mHead > mContainerSize-1) {
mHead = mHead-mContainerSize;
}
return true;
}
public int Front() {
if(isEmpty()) {
return -1;
}
return mContainer[mHead];
}
public int Rear() {
if(isEmpty()) {
return -1;
}
return mContainer[mTail];
}
public boolean isEmpty() {
return mHead == -1 && mTail == -1;
}
public boolean isFull() {
if(mContainerSize == 0) {
return true;
}
if(mHead == -1 && mTail == -1) {
return false;
}
return (mTail-mHead+1 == mContainerSize) || (mTail-mHead == -1);
}
}
循环队列官方代码实现:
/**
* @author 404小恐龙
* @version 1.8
* @date 2021/10/2 10:00
*/
class MyCircularQueue {
private int[] data;
private int head;
private int tail;
private int size;
/** Initialize your data structure here. Set the size of the queue to be k. */
public MyCircularQueue(int k) {
data = new int[k];
head = -1;
tail = -1;
size = k;
}
/** Insert an element into the circular queue. Return true if the operation is successful. */
public boolean enQueue(int value) {
if (isFull() == true) {
return false;
}
if (isEmpty() == true) {
head = 0;
}
tail = (tail + 1) % size;
data[tail] = value;
return true;
}
/** Delete an element from the circular queue. Return true if the operation is successful. */
public boolean deQueue() {
if (isEmpty() == true) {
return false;
}
if (head == tail) {
head = -1;
tail = -1;
return true;
}
head = (head + 1) % size;
return true;
}
/** Get the front item from the queue. */
public int Front() {
if (isEmpty() == true) {
return -1;
}
return data[head];
}
/** Get the last item from the queue. */
public int Rear() {
if (isEmpty() == true) {
return -1;
}
return data[tail];
}
/** Checks whether the circular queue is empty or not. */
public boolean isEmpty() {
return head == -1;
}
/** Checks whether the circular queue is full or not. */
public boolean isFull() {
return ((tail + 1) % size) == head;
}
}
双栈模拟队列:
public class d746 {
Stack<Integer> stack1 = new Stack<Integer>();
Stack<Integer> stack2 = new Stack<Integer>();
/**
* 压栈的方法
* @param node 被压入的元素
*/
public void push(int node) {
stack1.push(node);
}
/**
* 弹栈的方法
* @return 原先stack1被压入的第一个元素
*/
public int pop() {
if (stack2.empty()) {
/*
核心部分:
清空stack1
清空一次在stack2中压入相同的元素
返回压入的最后一个元素
便是原先stack1压入的第一个元素
*/
while (!stack1.empty()) {
stack2.push(stack1.pop());
}
}
return stack2.pop();
}
}
队列思想解决数据流的移动平均值:
package dc;
import java.util.LinkedList;
import java.util.Queue;
/**
* @author 404小恐龙
* @version 1.8
* @date 2021/10/2 10:05
*/
public class d13 {
/*
需求:数据流的移动平均值
MovingAverage m = new MovingAverage(3);
m.next(1) = 1
m.next(10) = (1 + 10) / 2
m.next(3) = (1 + 10 + 3) / 3
m.next(5) = (10 + 3 + 5) / 3
*/
public static void main(String[] args) {
MovingAverage m = new MovingAverage(3);
System.out.println(m.next(1));
System.out.println(m.next(10));
System.out.println(m.next(3));
System.out.println(m.next(5));
}
}
/**
* 使用队列的思想来解决滑动平均问题
*/
class MovingAverage {
private Queue<Integer> queue;
/*
移动窗口的范围
*/
private int maxSize;
//Initialize your data structure here.
public MovingAverage(int Size) {
queue = new LinkedList<Integer>();
maxSize = Size;
}
public double next(int value){
int sum = 0;
if(queue.size()>=maxSize){
/*
移除头元素
添加新元素
*/
queue.poll();
queue.offer(value);
} else{
queue.offer(value);
}
for(Integer x:queue){
sum+=x;
}
return (sum*1.0)/queue.size();
}
}
队列思想解决墙与门算法:最短路径模板
package dc;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Arrays;
import java.util.List;
/**
* @author 404小恐龙
* @version 1.8
* @date 2021/10/2 10:20
*/
public class d14 {
/*
队列的广度优先搜索
与树的层序遍历相同,是优化过后的BFS
同一层节点将在同一个循环中处理,保证每次循环结束时队列中都是同一层的元素
正好之前遇到过类似求最短路径的问题
层序遍历能按层,遍历到所有的节点,在此基础上求出最短路径
而深度优先类似与二叉树的中序遍历
补充一下队列知识:
// 移除队列头元素
queue.remove(); // 如果队列为空,会报 NoSuchElementException 异常
queue.poll(); // 如果队列为空,会返回null
// 添加元素
queue.add(1); // 如果队列满会报unchecked异常
queue.offer(1); // 如果队列满会返回false
// 在不移除的情况下返回队列头
queue.peek(); // 如果队列空,返回null
queue.element(); // 如果队列空,会报 NoSuchElementException 异常
*/
public static void main(String[] args) {
}
}
class Solution {
/*
墙与门
题目描述:
您将获得一个由这三个可能值初始化的m x n 2d网格。less
-1 - 墙 可以想象成障碍物
0 - 门 可以想象成目的地
INF - 空房间 可以想象成起点
这个程序可以封装成求最短路径算法
INF - 无限意味着一个空房间。咱们使用值2^31-1=2147483647表示inf,
于您能够假定到门的距离小于2147483647。
把每一个空房间填满到最近的门的距离。若是不可能到达一个门,应该用inf填充。
函数把每一个空房间填满到最近的门的距离。若是不可能到达一个门,应该用inf填充。
在程序中,我使用EMPTY表示空房间
*/
private static final int EMPTY = Integer.MAX_VALUE;
private static final int GATE = 0;
/*
初始化坐标轴
x:1表示向下,-1表示向上
y:1表示向右,-1表示向左
*/
private static final List<int[]> DIRECTIONS = Arrays.asList(
new int[] { 1, 0},
new int[] {-1, 0},
new int[] { 0, 1},
new int[] { 0, -1}
);
public void wallsAndGates(int[][] rooms) {
/*
m表示行数
n表示列数
*/
int m = rooms.length;
if (m == 0) return;
int n = rooms[0].length;
/*
所有的门入队
*/
Queue<int[]> q = new LinkedList<>();
for (int row = 0; row < m; row++) {
for (int col = 0; col < n; col++) {
if (rooms[row][col] == GATE) {
q.add(new int[] { row, col });
}
}
}
/*
广度优先遍历开始
*/
while (!q.isEmpty()) {
/*
获取当前门的行列坐标
*/
int[] point = q.poll();
int row = point[0];
int col = point[1];
/*
分别从上下左右四个方向进行排查
*/
for (int[] direction : DIRECTIONS) {
int r = row + direction[0];
int c = col + direction[1];
/*
如果超出边界或者它不是空房间(EMPTY)
跳过此次循环
下面两行代码不执行
*/
if (r < 0 || c < 0 || r >= m || c >= n || rooms[r][c] != EMPTY) {
continue;
}
/*
程序运行到此处
说明找到了空房间
这里的rooms[r][c]就是
二维数组中的INF
此时房间离门的距离+1
再次放入队列等待处理
*/
rooms[r][c] = rooms[row][col] + 1;
q.add(new int[] { r, c });
}
}
}
}
岛屿问题:深度优先搜索解决
class Solution1 {
private int count = 0;
/**
* 有多少个岛屿
* @param grid 二维数组
* @return 多少个岛屿
*/
public int numIslands(char[][] grid) {
if(grid.length == 0 || grid[0].length == 0){
return count;
}
/*
得到二位数字的行数和列数
*/
int m = grid.length;
int n = grid[0].length;
/*
遍历查找当前为1的元素
*/
for(int i=0;i < m;i++){
for(int j=0;j < n;j++){
if(grid[i][j] == '1'){
/*
程序运行到此处
开始递归查询
向四个方向扩散查找
直到查找完毕执行count++
*/
dfs(grid, i, j);
count++;
}
}
}
return count;
}
/**
* 上下左右方向查询
* @param grid 二维数组
* @param i 当前元素所在行
* @param j 当前元素所在列
*/
public void dfs(char[][] grid, int i, int j){
if(i < 0 || i >= grid.length || j < 0 || j >= grid[0].length || grid[i][j] == '0'){
return;
}
/*
访问过的grid设置为0
避免出现死循环
*/
grid[i][j] = '0';
dfs(grid, i - 1, j);
dfs(grid, i + 1, j);
dfs(grid, i, j - 1);
dfs(grid, i, j + 1);
}
}