【Java 数据结构】队列与OJ题

这篇具有很好参考价值的文章主要介绍了【Java 数据结构】队列与OJ题。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

java的oj题该怎么做,Java数据结构,数据结构,算法,java,队列
篮球哥温馨提示:编程的同时不要忘记锻炼哦!

我是作者,亦是读者。


目录

1、什么是队列? 

2、初识Queue

2.1 认识一下Queue

2.2 简单使用下Queue

3、模拟实现Queue

3.1 构造方法和成员属性

3.2 offer 方法

3.3 poll 方法

3.4  peek 方法

4、队列相关的OJ题

4.1 设计循环队列 (来源:LeetCode 难度:中等)  

4.2 用队列实现栈 (来源:LeetCode 难度:简单)

4.3 用栈实现队列 (来源:LeetCode 难度:简单)

4.4 最小栈 (来源:LeetCode 难度:中等) 


1、什么是队列? 

java的oj题该怎么做,Java数据结构,数据结构,算法,java,队列

队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out)

入队列:进行插入操作的一端称为队尾!

出队列:进行删除操作的一 端称为队头!

队列也可以数组和链表的结构实现,使用链表的结构实现更优一些,因为如果使用数组的结构, 出队列在数组头上出数据,效率会比较低。


2、初识Queue

2.1 认识一下Queue

java的oj题该怎么做,Java数据结构,数据结构,算法,java,队列

如图可见,Queue本质上是一个接口,被Deque(双端队列)继承,被LinkedList实现,所以Queue底层是通过链表来实现的,而Queue是不能实例化对象的, 所以我们想使用队列,则需要new一个LinkedeList对象,实现向上转型,这样就可以使用Queue中的方法了:

java的oj题该怎么做,Java数据结构,数据结构,算法,java,队列add 和 offer 都是入队列,这两个区别是当使用add时,一些队列有大小限制,如果想在一个满的队列中加入新的元素时,调用 add() 方法就会抛出一个 unchecked 异常,而调用 offer() 方法会返回 false。因此就可以在程序中进行有效的判断!

2.2 简单使用下Queue

public static void main(String[] args) {
    Queue<Integer> queue = new LinkedList<>();
    queue.offer(1);
    queue.offer(2);
    queue.offer(3);
    System.out.println(queue.peek()); //获取对头元素 -> 1
    System.out.println(queue.poll()); //出队头元素 -> 1
    System.out.println(queue.peek()); //获取对头元素 -> 2
    System.out.println(queue.isEmpty()); //判断队列是否为null -> false
    queue.clear(); //清空队列
    System.out.println(queue.isEmpty()); //判断队列是否为null -> true
}

3、模拟实现Queue

3.1 构造方法和成员属性

public class MyQueue {

    private class Node {
        private int val; //数据域
        private Node next; //指针域名

        private Node(int val) {
            this.val = val;
        }
    }
    //队头入,队尾出
    private Node head; //队头引用
    private Node last; //队尾引用
    private int size; //队列有效数据个数
}

3.2 offer 方法

// 队尾入队列
public boolean offer(int val) {
    Node newNode = new Node(val);
    // 如果是第一次入队列
    if (this.head == null) {
        this.head = newNode;
        this.last = newNode;
    } else {
        this.last.next = newNode;
        this.last = this.last.next;
    }
    this.size++;
    return true;
}

3.3 poll 方法

// 队头出队列
public int poll() {
    Node node = this.head;
    // 如果队列为null
    if (this.head == null) {
        throw new MyQueueIsEmptyException("队列为空!");
    } else {
        this.head = this.head.next;
    }
    this.size--;
    return node.val;
}

3.4  peek 方法

// 取队头元素
public int peek() {
    // 如果队列为null
    if (this.head == null) {
        throw new MyQueueIsEmptyException("队列为空!");
    } else {
        return this.head.val;
    }
}

至于size和empty方法,就交给各位小伙伴实现了,由于有了前面链表的基础,队列实现起来是比较简单的,所以更多希望阅读文章的初学者能下来多自己手写以下,画画图。


4、队列相关的OJ题

4.1 设计循环队列 (来源:LeetCode 难度:中等)  

题目:设计你的循环队列实现。 循环队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原则并且队尾被连接在队首之后以形成一个循环。它也被称为“环形缓冲器”。

循环队列的一个好处是我们可以利用这个队列之前用过的空间。在一个普通队列里,一旦一个队列满了,我们就不能插入下一个元素,即使在队列前面仍有空间。但是使用循环队列,我们能使用这些空间去存储新的值。

你的实现应该支持如下操作:

MyCircularQueue(k): 构造器,设置队列长度为 k 。
Front: 从队首获取元素。如果队列为空,返回 -1 。
Rear: 获取队尾元素。如果队列为空,返回 -1 。
enQueue(value): 向循环队列插入一个元素。如果成功插入则返回真。
deQueue(): 从循环队列中删除一个元素。如果成功删除则返回真。
isEmpty(): 检查循环队列是否为空。
isFull(): 检查循环队列是否已满。

解题思路:对于这道题来说,我们有很多种解题思路,但我们要注意一点,如何区分队列为空和队列满的情况?这里可以添加size属性记录,也可使用标记,也可也空一个位置出来区分,那么今天我们就空一个位置,那么如何区分队列空和队列满呢?见下图:

java的oj题该怎么做,Java数据结构,数据结构,算法,java,队列

对于循环队列的实现我们采用的时数组方案,有front和rear分别存储队头下标和队尾元素的后一个下标。至于更多需要注意细节的地方,比如修正front和rear的位置时,在代码中有对应的注释,查看即可:

public class MyCircularQueue {

    private int array[]; //存放数据的数组
    private int front; // 队头下标
    private int rear; // 队尾下标

    public MyCircularQueue(int k) {
        this.array = new int[k + 1]; //因为我们要浪费一个空间,所以需要多开辟一个空间
    }

    // 入队列
    public boolean enQueue(int value) {
        // 如果队列满的情况
        if (isFull()) {
            return false;
        }
        // 没有满就往队尾入元素
        this.array[this.rear] = value;
        // rear往前走一步,需要空出一个位置,所以当rear走到length-1时,需要修正下rear
        this.rear = (this.rear + 1) % this.array.length;
        return true;
    }

    // 出队列
    public boolean deQueue() {
        // 如果队列为null的情况
        if (isEmpty()) {
            return false;
        }
        // 从队头出队列,需要修正队头的位置
        this.front = (this.front + 1) % this.array.length;
        return true;
    }
    
    // 取队头元素
    public int Front() {
        // 如果队列为null的情况
        if (isEmpty()) {
            return -1;
        }
        return this.array[this.front]; //返回队头元素
    }

    // 取队尾元素
    public int Rear() {
        // 如果队列为null的情况
        if (isEmpty()) {
            return -1;
        }
        // 如果rear为0的情况,我们需要特殊处理
        int index = this.rear == 0 ? this.array.length - 1 : this.rear - 1;
        return this.array[index]; //返回队尾元素
    }

    // 判断队列是否为空
    public boolean isEmpty() {
        // 当front和rear相遇了,则表示队列中没有元素
        return this.front == this.rear;
    }

    // 判断队列是否满了
    public boolean isFull() {
        // 因为我们会浪费一个空间,所以rear+1等于front就满了
        // 但是我们要rear防止越界,所以要进行修正:(this.rear + 1) % this.array.length
        return (this.rear + 1) % this.array.length == this.front;
    }
}

4.2 用队列实现栈 (来源:LeetCode 难度:简单)

题目:请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(push、top、pop 和 empty)。

实现 MyStack 类:

void push(int x) 将元素 x 压入栈顶。
int pop() 移除并返回栈顶元素。
int top() 返回栈顶元素。
boolean empty() 如果栈是空的,返回 true ;否则,返回 false 。

解题思路:这道题的解题思路并不难,我们只需要定义两个队列,入栈的时候往不为null的队列入,出栈的时候先将不为空的队列的size()-1个元素全部放到为空的队列中,剩余最后一个元素直接出栈即可,由于取栈顶元素不用删除元素,所以剩余的最后一个元素还要放入另一个队列中,至于更详细的内容可以配合下面代码和注释阅读:

class MyStack {
    private Queue<Integer> qu1;
    private Queue<Integer> qu2;

    public MyStack() {
        this.qu1 = new LinkedList<>();
        this.qu2 = new LinkedList<>();
    }
    
    public void push(int x) {
        // 两个队列都为null的情况
        if (this.qu1.isEmpty() && this.qu2.isEmpty()) {
            this.qu1.offer(x);
            return;
        }

        // 哪个队列不为null往哪个队列中入元素
        if (!this.qu1.isEmpty()) {
            this.qu1.offer(x);
        } else {
            this.qu2.offer(x);
        }
    }
    
    public int pop() {
        // 如果两个队列都为空的情况下,就不能出队操作
        if (empty()) {
            return -1;
        }
        // 先将不为空的队列的size-1个元素全部放到为空的队列中
        if (!this.qu1.isEmpty()) {
            while (qu1.size() - 1 != 0) {
                qu2.offer(qu1.poll());
            }
            return qu1.poll(); //返回最后一个元素
        } else {
            while (qu2.size() - 1 != 0) {
                qu1.offer(qu2.poll());
            }
            return qu2.poll(); //返回最后一个元素
        }
    }
    
    public int top() {
        // 如果队列为null
        if (empty()) {
            return -1;
        }
        int ret = 0; //保留剩余最后一个栈顶元素的变量
        // 先将不为空的队列的size-1个元素全部放到为空的队列中
        if (!this.qu1.isEmpty()) {
            while (qu1.size() - 1 != 0) {
                qu2.offer(qu1.poll());
            }
            ret = qu1.peek();
            qu2.offer(qu1.poll());
        } else {
            while (qu2.size() - 1 != 0) {
                qu1.offer(qu2.poll());
            }
            ret = qu2.peek();
            qu1.offer(qu2.poll()); //取栈顶元素不能删除掉,还得入另一个队列中去
        }
        return ret;
    }
    
    public boolean empty() {
        return this.qu1.isEmpty() && this.qu2.isEmpty(); //两个队列都为空,栈才为空
    }
}

4.3 用栈实现队列 (来源:LeetCode 难度:简单)

题目:请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(push、pop、peek、empty)。

实现 MyQueue 类:

void push(int x) 将元素 x 推到队列的末尾
int pop() 从队列的开头移除并返回元素
int peek() 返回队列开头的元素
boolean empty() 如果队列为空,返回 true ;否则,返回 false

解题思路:这道题我们可以这样做,定义两个栈,分别是pushStack和popStack,入队统一都入到pushStack栈中,出队头元素都从popStack中出,如果popStack是空的情况,就先将pushStack栈中所有的元素放入popStack中,再出栈顶元素。 至于判断队列是否为空,需要满足 pushStack和popStack都为空,队列才为空!

class MyQueue {
    private Stack<Integer> pushStack;
    private Stack<Integer> popStack;
    public MyQueue() {
        this.pushStack = new Stack<>();
        this.popStack = new Stack<>();
    }
    
    public void push(int x) {
        // 入队列都在pushStack中
        this.pushStack.push(x);
    }
    
    public int pop() {
        // 出队列都从popStack出
        if (popStack.empty()) {
            // 把pushStack栈中的元素都放到popStack栈中
            while (!pushStack.empty()) {
                popStack.push(pushStack.pop());
            }
        }
        if (!popStack.empty()) {
            return popStack.pop();
        } else {
            return -1;
        }
    }
    
    public int peek() {
        // 取队头元素都从popStack中取
        if (popStack.empty()) {
            // 把pushStack栈中的元素都放到popStack栈中
            while (!pushStack.empty()) {
                popStack.push(pushStack.pop());
            }
        }
        if (!popStack.empty()) {
            return popStack.peek();
        } else {
            return -1;
        }
    }
    
    public boolean empty() {
        return pushStack.empty() && popStack.empty();
    }
}

4.4 最小栈 (来源:LeetCode 难度:中等)

题目:设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。

实现 MinStack 类:

MinStack() 初始化堆栈对象。
void push(int val) 将元素val推入堆栈。
void pop() 删除堆栈顶部的元素。
int top() 获取堆栈顶部的元素。
int getMin() 获取堆栈中的最小元素。

解题思路:这道题一看就需要用到两个栈,一个栈入数据,一个栈始终压入最小值,如何操作呢?这里我们可以定义两个栈,分别是stack和minStack,入栈的时候入stack这个栈,如果是第一次入栈,则当前入栈元素为最小值,同时也需要入minStack栈中,如果后续入栈元素小于或等于minStack栈顶元素,则也需要入minStack栈,如果比minStack栈顶元素大,则不需要入minStack栈了,出栈的时候,判断stack栈如果与minStack栈元素相等,则minStack也要出栈顶元素!

java的oj题该怎么做,Java数据结构,数据结构,算法,java,队列

public class MinStack {
    private Stack<Integer> stack;
    private Stack<Integer> minStack;
    public MinStack() {
        this.stack = new Stack<>();
        this.minStack = new Stack<>();
    }
    
    public void push(int val) {
        // 如果stack为null,表示第一次入栈,
        // 此时入栈的元素也是此时栈中最小值,也要入minStack栈
        if (this.stack.isEmpty()) {
            this.stack.push(val);
            this.minStack.push(val);
            return;
        }
        this.stack.push(val);
        // 如果stack栈顶元素小于等于minStack栈顶元素,则也需要入minStack栈中
        if (this.stack.peek() <= this.minStack.peek()) {
            this.minStack.push(val);
        }
    }

    // 出栈
    public void pop() {
        if (this.stack.isEmpty()) {
            return;
        }
        // 如果出栈元素与minStack元素相等,minStack也要出栈
        if (this.stack.pop().equals(this.minStack.peek())) {
            this.minStack.pop();
        }
    }

    // 取栈顶元素
    public int top() {
        if (this.stack.isEmpty()) {
            return -1;
        } else {
            return this.stack.peek();
        }
    }

    // 取栈中最小元素
    public int getMin() {
        if (this.stack.isEmpty()) {
            return -1;
        } else {
            return this.minStack.peek();
        }
    }
}

下期预告:【Java 数据结构】二叉树文章来源地址https://www.toymoban.com/news/detail-815745.html

到了这里,关于【Java 数据结构】队列与OJ题的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Java--数据结构】链表经典OJ题详解(上)

    欢迎关注个人主页:逸狼 创造不易,可以点点赞吗~ 如有错误,欢迎指出~ 目录 谈谈头插、头删、尾插、头插的时间复杂度 反转一个单链表  链表的中间结点 返回倒数第k个结点 合并两个链表 头插和头删的时间复杂度为O(1), 尾插和尾删的时间复杂度为O(n) (因为尾插和

    2024年04月27日
    浏览(33)
  • 【数据结构】栈与队列经典oj题

    🚀write in front🚀 📜所属专栏:初阶数据结构 🛰️博客主页:睿睿的博客主页 🛰️代码仓库:🎉VS2022_C语言仓库 🎡您的点赞、关注、收藏、评论,是对我最大的激励和支持!!! 关注我,关注我,关注我 , 你们将会看到更多的优质内容!!   栈两种线性表示都能实现

    2024年02月03日
    浏览(42)
  • 【数据结构】——栈与队列(附加oj题详解)深度理解

    1.栈的定义 栈: 栈是仅限与在表尾进行插入或者删除的 线性表 我们把 允许一端插入和删除的一端叫做栈顶,另一端叫栈底,不含任何元素的栈叫做空栈 ,栈又叫做后进先出的线性表,简称 LIFO 结构 2.栈的理解 对于定义里面的在表尾进行插入和删除, 这里的表尾就是栈顶,

    2024年03月26日
    浏览(54)
  • 【LeetCode】【数据结构】栈与队列必刷OJ题

    👀 樊梓慕: 个人主页   🎥 个人专栏: 《C语言》《数据结构》《蓝桥杯试题》《LeetCode刷题笔记》 🌝 每一个不曾起舞的日子,都是对生命的辜负 目录 前言: 【LeetCode】20.有效的括号(栈的括号匹配问题) 【LeetCode】225.用队列实现栈 【LeetCode】232.用栈实现队列 【LeetCo

    2024年02月13日
    浏览(43)
  • 数据结构刷题训练:设计循环队列(力扣OJ)

    目录 文章目录 前言 1. 题目:设计循环队列 2. 思路 3. 分析  3.1 定义循环队列  3.2 创建队列  3.3 判空和判满  3.4 入队  3.5 出队  3.6 取队头队尾数据  3.7 销毁队列  4. 题解 总结         当谈到队列数据结构时,很多人可能会想到普通的队列,即先进先出(FIFO)的数据结

    2024年02月13日
    浏览(47)
  • 数据结构刷题训练:用栈实现队列(力扣OJ)

    目录 前言 1. 题目:用栈实现队列 2. 思路 3. 分析  3.1 定义 “ 队列 ”  3.2 创建队列 3.3 入队  3.4 队头数据  3.5 出队  3.6 判空和销毁 4.题解 总结         栈和队列是数据结构中的两个重要概念,它们在算法和程序设计中都有着广泛的应用。本文将带你深入了解如何使用

    2024年02月13日
    浏览(39)
  • 万字精讲——数据结构栈与队列必会OJ练习

    W...Y的主页 💕 代码库分享 😊 在之前的博客中,我们学习了栈与队列的基本内容,并且实现了栈与队列。今天我们进行刷题训练,走进栈与队列的世界中去感受一番!!! 目录 括号匹配问题  使用队列实现栈 用栈实现队列 设计循环队列 给定一个只包括  \\\'(\\\' , \\\')\\\' , \\\'{

    2024年02月10日
    浏览(48)
  • 数据结构OJ题

    目录 1.字符串左旋  2.字符串旋转结果 3.旋转数组 4.移除元素 本篇主要是讲解一些OJ题目。 字符串左旋 实现一个函数,可以左旋字符串中的k个字符 例如: ABCD左旋一个字符得到BCDA ABCD左旋两个字符得到CDAB 方法1【暴力求解】 翻转1个字符 创建一个中间变量tmp,用于存储翻转

    2024年02月06日
    浏览(40)
  • 数据结构OJ:最小栈

    OJ链接 简而言之,题目就是要我们实现一个栈,这个栈能够快速查找最小值,要求时间复杂度O(1),也就是说不能循环暴力查找 思路: 也许很多人一看到这个题目就有思路,就是定义一个min变量,入栈的时候如果元素比min小就更新min 但是这么做会有一个问题,如果最小值被p

    2024年02月11日
    浏览(50)
  • 数据结构——链表OJ题

    目录   1.给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 。 2.给定一个带有头结点 head 的非空单链表,返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点。 3.变形题:找到链表中倒数第k个

    2024年02月21日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包