剑指offer刷题

一. 链表
二. 队列
三. 栈

一. 链表

JZ3 从尾到头打印链表
JZ14 链表中倒数第k个结点
JZ15 反转链表 链表
JZ16 合并两个排序的链表
JZ25 复杂链表的复制
JZ26 二叉搜索树与双向链表
JZ36 两个链表的第一个公共结点
JZ46 孩子们的游戏(圆圈中最后剩下的数)
JZ55 链表中环的入口结点
JZ56 删除链表中重复的结点
JZ62 二叉搜索树的第k个结点

3. 从尾到头打印链表 【链表】【栈】

牛客剑指offer题目

  • 思路:
    只是需要将链表的值打印出来,所以没那么复杂,涉及到反转,只需要利用Stack就可以了。
  • 代码:
/**
*    public class ListNode {
*        int val;
*        ListNode next = null;
*
*        ListNode(int val) {
*            this.val = val;
*        }
*    }
*
*/
import java.util.ArrayList;
import java.util.Stack;
public class Solution {
    public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
        //返回链表中的值就可以了,考虑用栈
        ArrayList<Integer> result = new ArrayList<>();
        Stack<Integer> stack=new Stack<>();
        while( listNode != null){
            stack.push(listNode.val);
            listNode=listNode.next; //记得传完值以后,要让节点指向下一个节点啊
        }
        while(!stack.isEmpty()){
            result.add(stack.pop());
        }
        return result;
    }
}
  • 知识点:
    导包:import java.util.ArrayList;以及import java.util.Stack;
    注意,使用一个节点以后,要将下一个节点指向给当前的节点啊

14. 链表中倒数第k个结点【链表】

牛客剑指offer题目

  • 思路:
    假设6个节点 1 2 3 4 5 6,那么倒数第2个节点其实就是正数第5个节点,k=2,5=6+1-2。
    所以代码就先,求出链表得长度,然后加1减去k就是正数第几个节点,我们在遍历链表,把这个节点作为返回值即可。
  • 代码:
public ListNode FindKthToTail(ListNode head,int k){
        //假设6个节点,1 2 3 4 5 6 倒数第2个,就是正数第5个,k=2,求正数第5个节点
        //先求链表长度
        int size=0;
        ListNode pHead=head;
        while(pHead!=null){
            size++;
            pHead=pHead.next;
        }
        
        if(k>size) return null;  //注意判断k是否超出范围啊
        else{
            int head_num=size+1-k;  //6+1-2=5
            pHead=head;
            for(int i=1;i<head_num;i++){
                pHead=pHead.next;
            }
            return pHead;
        }
    }
  • 知识点:
    注意求链表长度得代码块。

15. 反转链表【链表】

牛客剑指offer题目

  • 思路:
    反转链表需要三个节点,当前节点head,当前节点得前一个节点pre以及当前节点得后一个节点next。循环:只要当前节点head不为空,就一直交换。
  • 代码:
public ListNode ReverseList(ListNode head){
        //需要三个节点之间得交换来反转链表
        ListNode pre=null;
        ListNode next=null;
        while(head!=null){//head没到null就说明,head指向得不是最后一个节点,就要一直交换
            next=head.next;//首先head指向得是当前节点,那么在最开始head是头节点得时候,pre=null没问题,但是next不应该是null,所以先给next赋值
            head.next=pre;//head是当前节点,因为要反转链表,所以当前节点得next应该是前一个节点,也就是pre
            pre=head; //前两行代码就算转换完毕了,接下来就是移动节点,所有得节点后移,pre就应该是刚才得当前节点
            head=next; //next应该给当前节点赋值
        }
        return pre;
        //最终返回得应该是pre,因为当head指向到最后一个节点的时候,head并不是null,循环执行以后,head指向了null,
        // 在判断发现循环条件不满足,
        // 但是此时的head指向的是null,pre才是最后一个节点,也就是现在的头节点,所以返回pre
    }
  • 知识点:
    注意循环里面交换的过程需要三个节点进行交换;
    注意最后的返回值;

16.合并两个排序的链表【链表】

牛客剑指offer题目

  • 思路:
    先比较两个链表的头节点,list1和list2,假设list1的头节点小,那么将list1赋值给list,注意因为最开始假设list是null,所以要将整个list1赋给list,而不单单是val,这样无效。然后修改list的next的值,利用递归比较list1剩余的节点以及list2的节点。
  • 代码:
public ListNode Merge(ListNode list1,ListNode list2){
        ListNode list=null;
        if(list1==null){
            return list2;
        }else if(list2==null){
            return list1;
        }

        if(list1.val<=list2.val){
//            list.val=list1.val;
            list=list1;  // 上面那样写法不对,因为list最开始是null,所以不存在val,
            //你要直接将list1给list,然后再修改next得值
            list.next=Merge(list1.next,list2);
        }
        if(list1.val>list2.val){
//            list.val=list2.val;
            list=list2; // 上面那样写法不对,因为list最开始是null,所以不存在val,
            //你要直接将list2给list,然后再修改next得值
            list.next=Merge(list1,list2.next);
        }
        return list;
    }

25.复杂链表的复制【链表】【HashMap】

牛客剑指offer题目

  • 思路:
    首先需要建立一个新的链表,这个新的链表要和原链表建立起来联系,选择使用hashmap映射将新旧链表建立起来联系,新链表存入label值。然后再将新链表连接起来,即存入next和random的值。
  • 代码:
//要想复制得到新的链表,首先你得创建一个新的链表,而且新的链表要和原链表建立起来联系
    public RandomListNode Clone(RandomListNode pHead){
        //先利用hashmap建立起来原链表和新链表的关系
        HashMap<RandomListNode,RandomListNode> map=new HashMap<>();//建立原链表与新链表的关系
        RandomListNode p1=pHead;////用来创建新旧链表的对应节点关系
        while(p1!=null){
            map.put(p1,new RandomListNode(p1.label)); //把label逐个存入到新的链表中
            p1=p1.next;
        }//至此,新链表和旧链表关系创建成功,但是新链表只有label值,next和random都还为null

        RandomListNode p2=pHead;// 用来存储next和random指针
        while(p2!=null){
            //由于最后一个节点的next可能为null,所以需要判断一下,是否是最后一个节点
            //但是random就没有为null的节点,所以不需要判断
            if(p2.next!=null){
                map.get(p2).next=map.get(p2.next);  //map.get(p2)表示得到新链表的节点,这个节点的next值应当存储下一个节点,
                // 下一个节点就应该是刚才建立的新节点new RandomListNode的第二个节点
            }else{
                map.get(p2).next=null;
            }
            map.get(p2).random=map.get(p2.random);
            p2=p2.next;
        }
        return map.get(pHead);
    }

26.二叉搜索树与双向链表【二叉树】【链表】【ArrayList】

牛客剑指offer题目

  • 思路:
    二叉搜索树,左子树的所有节点的值小于根节点的值,右子树所有节点的值大于根节点的值,左<根<右。
    将二叉搜索树变为排序好的链表实际上就是中序遍历,然后将中序的结果串起来。
    中序遍历参考博客
  • 代码:
 ArrayList<TreeNode> list=new ArrayList<>();
    public TreeNode Convert(TreeNode pRootOfTree){
        if(pRootOfTree == null) return null;
        //二叉搜索树,左子树的所有节点的值小于根节点的值,右子树所有节点的值大于根节点的值,左<根<右
        //将二叉搜索树变为排序好的链表实际上就是中序,然后将中序的结果串起来
        Trans(pRootOfTree); //得到排序好的list
        //2 5 9 串联起来
        for(int i=0;i<list.size()-1;i++){
            list.get(i).right=list.get(i+1);//当前值的右节点 存的应该是list中的下一个值
            list.get(i+1).left=list.get(i); //i+1 的left存的是前一个节点信息
            //这样写的话,就不涉及到特殊的第一个节点和最后一个节点了
        }
        return list.get(0);
    }
    public void Trans(TreeNode pRootOfTree){
        if(pRootOfTree==null) return ;
        else {
            Trans(pRootOfTree.left);
            list.add(pRootOfTree);
            Trans(pRootOfTree.right);
        }
    }
  • 知识点:
    将list串联起来为双线链表的时候,注意i的取值,从0开始到

36.两个链表的第一个公共结点【链表】

牛客剑指offer上题目

  • 思路:
    求2个链表的长度,然后让长的链表先走差个长度。在同时遍历两个链表,遇到的第一个相同的节点作为返回值即可。
  • 代码:
public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2){
        //求2个链表的长度
        int count1=0;
        ListNode p1=pHead1;
        while (p1!=null){
            count1++;
            p1=p1.next;
        }

        int count2=0;
        ListNode p2=pHead2;
        while (p2!=null){
            count2++;
            p2=p2.next;
        }

        //让长的链表先走  两个长度之差的  步数
        int sub=count1-count2;
        p1=pHead1;
        p2=pHead2;
        if(sub>0){ //说明链表1长
            for(int i=0;i<sub;i++){
                p1=p1.next;
            }
        }else {
            sub=-sub;
            for (int i=0;i<sub;i++){
                p2=p2.next;
            }
        }

        //2个链表一起走,相同的那个节点就作为返回值
        while (p1!=null && p2!=null){
            if(p1==p2) return p1;
            p1=p1.next;
            p2=p2.next;
        }
        return null;

46.孩子们的游戏(圆圈中最后剩下的数)【数组】【循环】【需要仔细研读】

牛客网上剑指offer题目

  • 思路:
    先将元素存入到list中。list中只要元素数量大于1,就要一直删除元素。删除元素靠循环m,没循环一次删除一个元素,所以需要一个额外的元素cur来记录当前位置,从当前位置往后不断循环。
  • 代码:
public int LastRemaining_Solution(int n, int m){
        if(n<1||m<1) return -1;  //注意特殊情况
        ArrayList<Integer> list=new ArrayList<>();
        for(int i=0;i<n;i++){
            list.add(i);
        } //将孩子序号存入到一个list中  [0 1 2 3 4 5 6]  m=3
        int cur=-1;  //指向当前指针
        while(list.size()>1){
            for(int i=0;i<m;i++){//控制循环次数,每到这个循环执行一次删除一个元素
                cur++;
                if(cur==list.size()) cur=0;
            }//循环执行完一遍,删除一个元素
            list.remove(cur);//删除这个元素以后,cur需要变化一下   删除2以后,变为[0 1 3 4 5 6] 此时cur=2,但是下一次循环中需要cur为2,所以这里先递减一次
            cur--;
        }
        return list.get(0);
    }

55.链表中环的入口结点

牛客网上剑指offer题目

  • 思路:
    先判断是否有环,两个指针都从头开始走,一个一次走一步,一个一次走两步,如果有环那么快和慢指针一定会相遇,如果没环,那么快指针同时快指针的next都会指向null。
    然后判断环中节点的个数,刚才的两个相遇的指针一定是环中的点,当这个环的点再次回到这个点,走了几步就是环中节点的个数。
    然后一个指针从头开始,另一个从环的节点个数那里开始,两者相遇就是环的开端。
  • 代码:
if(pHead == null){
            return null;
        }
        // 判断是否是环,两个指针从头节点开始,slow一次走一个,fast一次走俩个,
        //如果是环,fast总会返回来和slow相遇,如果不是环,fast走到尾节点也不会和slow相遇
        boolean isHuan = false; //默认不是环
        ListNode slow=pHead;
        ListNode fast=pHead;
        while(fast!=null && fast.next!=null){ //fast没到尾节点,就一直往后走,到尾节点,也没相遇,那就不是环
            slow=slow.next;
            fast=fast.next.next;
            if(slow == fast){
                isHuan = true;
                break;
            }
        }
         
        //如果不是环,那么返回null
        if(!isHuan)  {
            return null;
        }else{
            //如果是环那么,确定环中节点的个数,刚才相遇的节点一定是环中的节点,
        //所以从这个节点开始,在回到这个节点所走的步数也就是环中节点的个数了
            int n=1;
        // fast和slow现在指的是同一个节点,相遇的那个节点
            fast=fast.next;
            while(fast!=slow){
                fast=fast.next;
                n++;
            }   //n是环中节点的个数
         
        //找到节点的入口,一个节点从头开始,另一个节点从节点长度那么长开始,相遇的节点就是环的入口
            slow = pHead;
            fast = pHead;
            for(int i=0;i<n;i++){
                fast=fast.next;
            }
        //然后每个节点走一步,直到相遇,则为节点的入口
            while(slow!=fast){
                slow=slow.next;
                fast=fast.next;
            }
        }       
        return fast;
    }

56. 删除链表中重复的结点

牛客网上剑指offer答案

  • 思路:
    有一点很重要的是,循环链表的时候,需要注意最后一个节点,当p指向最后一个节点的时候,p的next是null,如果你使用p.next!=null作为判断条件是可以的,但是如果你后面写p.next.val会发生异常,因为没有val这个值,所以有时我们考虑的是判断while (p.next!=null)

    先将重复的元素存入到set集合中。然后先处理头节点,看看头节点是否是重复元素。然后遍历原链表,将原链表中的元素逐个取出来,看看set中是否有,如果有,新链表中我们不存这个元素,跳过这个元素,set中没有这个元素,新链表中就要这个元素。

  • 代码:

public ListNode deleteDuplication(ListNode pHead){
        HashSet<Integer> set=new HashSet<>();
        ListNode p=pHead;
        while (p.next!=null){
            //到最后一个指针的时候,是p.next为null,因为后面用到了p.next.val,空指针是没有val的,所以这里只能写p.next
            if(p.val == p.next.val) set.add(p.val);
            p=p.next;
        }
        //重新组合一个链表作为返回值,首先单独处理头节点
        while (pHead!=null && set.contains(pHead.val)){
            pHead=pHead.next;
        }
        if(pHead==null) return null;
        ListNode pre=pHead;
        ListNode cur=pHead.next;
        while (cur!=null){
            if(set.contains(cur.val)){
                pre.next=cur.next;
                cur=cur.next;
            }else{
                pre=pre.next;
                cur=cur.next;
            }
        }
        return pHead;
    }

62.二叉搜索树的第k个结点

牛客网上剑指offer题目

  • 思路:
    二叉搜索树,想要编程排序好的链表,直接中序遍历即可。
    然后在链表中找到第k个节点,需要注意的是,链表有size这个函数,不用自己写这个函数。
  • 代码:
ArrayList<TreeNode> list=new ArrayList<>();
    TreeNode KthNode(TreeNode pRoot, int k){
        Trans(pRoot);
        if(k>=1 && list.size()>=k) {
            return list.get(k-1);  //链表的大小是可以直接利用函数的,不用自己遍历求啊、
        }
        return null;
    }
    public void Trans(TreeNode root){ //中序遍历
        if(root == null) return ;
        Trans(root.left);
        list.add(root);
        Trans(root.right);
    }

二. 队列

JZ5 用两个栈实现队列
JZ22 从上往下打印二叉树
JZ59 按之字形顺序打印二叉树
JZ60 把二叉树打印成多行
JZ61 序列化二叉树

5. 用两个栈实现队列【队列和栈】

牛客剑指offer题目

  • 思路:
    栈是先进后出,队列是先进先出。用两个栈实现队列的,入队和出队函数。
    入队,没什么好说的,就直接放入元素就可以了,也不需要返回值,所以直接存到stack1中记录即可。
    主要是出队的时候,注意是要先入队的先出,所以需要将元素从stack1中导入到stack2中,然后再tsack2出队,出队元素就是stack2中的顶级元素,这个元素是最先进入栈中的那个元素。
    还有一点需要注意的是,出队以后,方便其他元素下一次入队,是进入到stack1中,所以出队以后,需要将stack2中的元素再放回stack1中。

  • 代码:

//第5题:用两个栈实现队列
    Stack<Integer> stack1 = new Stack<Integer>();
    Stack<Integer> stack2 = new Stack<Integer>();

    public void push(int node) {
        stack1.push(node);  //入队,没什么好说的,就直接放入元素就可以了,也不需要返回值,所以直接存到stack1中即可
    }

    public int pop() {
        //主要是出队的时候,注意是要先入队的先出,所以需要将元素从stack1中导入到stack2中,然后再出队,出队元素就是stack2中的顶级元素
        //还有一点需要注意的是,出队以后,方便下一次入队,是进入到stack1中,所以出队以后,需要将stack2中的元素再放回stack1中
        while(!stack1.isEmpty()){
            stack2.push(stack1.pop());
        }
        int result= stack2.pop();
        while(!stack2.isEmpty()){
            stack1.push(stack2.pop());
        }
        return result;
    }
  • 知识点:
    补充用两个队列实现栈:
    压入元素,没什么好说的和栈的操作一样,先随便用一个队列存放压入的元素。
    出栈的时候,需要注意q1中入队1 2 3 出栈应该出3,所以我们一个一个出队,不是顶层的元素就出队之后存放到q2中。
    出掉3以后,再将q2中的元素存回q1中,方便下一次其他元素入队
//第5题补充,两个队列实现栈
    Queue<Integer> queue1=new LinkedList<>();
    Queue<Integer> queue2=new LinkedList<>();

    public void push(int node) {//压入元素,没什么好说的和栈的操作一样,先随便用一个队列存放压入的元素
        queue1.offer(node);
    }
    public int pop(){
        //出栈的时候,需要注意q1中入队1 2 3 出栈应该出3,所以我们一个一个出队,不是顶层的元素就出队之后存放到q2中,
        // 出掉3以后,再将q2中的元素存回q1中,方便下一次其他元素入队
        while (queue1.size()!=1){
            queue2.offer(queue1.poll());
        }
        int result=queue1.poll();
        while(!queue2.isEmpty()){
            queue1.offer(queue2.poll());
        }
        return result;
    }

也不确定代码错还是队,哪天遇到题验证一下吧。

21.从上往下打印二叉树【二叉树】【打印】【队列】

牛客剑指offer题目

  • 思路:
    打印二叉树需要借助队列,将根节点先存入队列,然后只要队列不为空,就要一直循环,然后将队列中的节点逐个冒出,将值存入list中,然后把左右子节点再依次存放到队列中。
  • 代码:
//从上往下打印二叉树
    //打印链表需要借助队列
    public ArrayList<Integer> PrintFromTopToBottom(TreeNode root) {
        ArrayList<Integer> list=new ArrayList<>();
        if(root==null) return list;
        Queue<TreeNode> queue=new LinkedList<>();
        queue.offer(root);
        while(!queue.isEmpty()){
            TreeNode temp=queue.poll();
            list.add(temp.val);
//            queue.offer(temp.left);
//            queue.offer(temp.right);
// 这样写是错的,一定要先判断是否为空再offer值,不然offer,提供的是null
            if(temp.left!=null)  queue.offer(temp.left);
            if(temp.right!=null) queue.offer(temp.right);
        }
        return list;
    }

59. 按之字形顺序打印二叉树

  • 思路
    引入size大小和是否反转的参数。
  • 代码
public ArrayList<ArrayList<Integer> > Print(TreeNode pRoot) {
        ArrayList<ArrayList<Integer>> result = new ArrayList<>();
        if(pRoot == null) return result;
        
        Queue<TreeNode> q=new LinkedList<TreeNode>();  //存储节点
        q.offer(pRoot);
        boolean rev=false;//是否反转存入元素
        
        while(!q.isEmpty()){
            ArrayList<Integer> list=new ArrayList<>();
            int size = q.size(); //每行中 队列元素的个数
            
            for(int i=0;i<size;i++){
                TreeNode temp = q.poll();
                if(temp == null) continue;
                if(!rev){
                    list.add(temp.val);
                }else{
                    list.add(0,temp.val);
                }
                q.offer(temp.left);  //把元素的值存入进去以后就要把他的节点送入队列中,
                //这一行的size已经确定了,送进队列中不会影响这一行的取值,下一行会重新判断size的
                q.offer(temp.right);
            }
            if(list.size()>0){  //注意如果list中没有元素了,就不要存入元素了啊,所以需要判断一下
                result.add(list);
            }
            rev = !rev;
        }
        return result;
    }

60.把二叉树打印成多行

牛客网上剑指offer题目

  • 思路:
    需要引入一个size的参数,每次循环size大小,将队列中的变量取出来。
  • 代码:
ArrayList<ArrayList<Integer> > Print(TreeNode pRoot) {
        ArrayList<ArrayList<Integer>> result = new ArrayList<>(); //result里面存的是list
        if(pRoot == null) return result;
        Queue<TreeNode> q = new LinkedList<>();  //用来存储每行的节点,逐个存入,逐个冒出
        q.offer(pRoot);
        while(!q.isEmpty()){  //队列不为空的时候才能往外取元素
            ArrayList<Integer> list=new ArrayList<>(); //用来存储每行的元素
            //因为每一行的元素是独立的,所以要提前定义好一个size,在取元素的时候,取走一个要存入这个元素的左右节点,
            //所以提前定义size,取出size大小的元素即可
            int size=q.size();
            for(int i=0;i<size;i++){
                TreeNode temp=q.poll();  //把每行中元素,从队列的元素取出来
                //由于一行中不一定有几个节点,所以定义一个临时变量temp逐个取
                list.add(temp.val);  //取出节点以后,要把这个节点的左右节点存到队列中,下一次循环用到
                if(temp.left != null) q.offer(temp.left);
                if(temp.right != null) q.offer(temp.right);
            }
            if(!list.isEmpty()){  //如果链表不空,才放到result中
                result.add(list);
            }
        }
        return result;
    }

61. 序列化二叉树

牛客网上剑指offer题目
不会,有点不理解

三. 栈

JZ20 包含min函数的栈
JZ21 栈的压入、弹出序列
JZ5 用两个栈实现队列
JZ62二叉搜索树的第k个结点

20. 包含min函数的栈【栈】【迭代器】

牛客剑指offer题目

  • 思路:
    有两种方法:方法1:剑指offer上的方法,利用一个辅助栈,基础栈中每存入一个元素,辅助栈中就存入最小的元素。详细可以参考书上的解析,代码可以参考链接中的武汉孙一峰的解析
    方法2:就是利用迭代器找到最小值返回最小值。
  • 代码:
    //包含min函数的栈
    //有两种方法:一种是借助辅助栈使用剑指offer书上的方法
    //一种是使用迭代器的方法

    //使用迭代器的方法比较简单,先使用迭代器的方法:
    Stack<Integer> stack=new Stack<>();
    public void push(int node) {
        stack.push(node);
    }

    public void pop() {
        stack.pop();
    }

    public int top() {
        return stack.peek();
    }

    public int min() {
        //迭代器的使用,需要导包
        Iterator<Integer> it =stack.iterator();
        int min=stack.peek();
        int tmp=0;
        while (it.hasNext()){
            tmp=it.next();//只是用一次
            if(min>tmp) min=tmp;
        }

//        Iterator it =stack.iterator();
//        int min=stack.peek();
//        while (it.hasNext()){
//            if(min>it.next()) min=it.next();
//        } // 错误示范。错误原因:每次使用it.next都会是下一个元素了,所以循环中多次使用next肯定是有问题的
        return min;
    }
  • 知识:
    最主要的就是这个迭代器的错误使用,迭代器再使用的时候,我犯了一个错误就是在循环中多次使用了next,但是实际上,每次使用next都是使用的下一个元素,所以以后在使用next的时候,要先将其赋值给一个tmp变量,然后使用tmp去计算。

21.栈的压入、弹出序列【栈】

牛客剑指offer题目

  • 思路:
    栈中每次存入一个元素,就和popA去比较,相同就弹出,且popA进入下一个元素
    如果栈顶元素和popA的首个元素相等,那么需要出栈,
    出栈以后是要继续判断栈顶元素和popA的下一个元素是否相等的,
    如果相等要继续出栈,不相等才进行下一轮的进栈,

  • 代码:

public boolean IsPopOrder(int [] pushA,int [] popA){
        // 对于栈来说,长度是属性 
        if(pushA.length == 0 || popA.length== 0 || pushA.length != popA.length){
            return false;
        }
        
        int j=0;
        Stack<Integer> stack=new Stack<>();
        for(int i=0;i<pushA.length;i++){
            stack.push(pushA[i]);  //先把元素放入栈中,看看能不能把栈中的元素清空,能清空返回true
            
            //栈中每次存入一个元素,就和popA去比较,相同就弹出,且popA进入下一个元素
            //如果栈顶元素和popA的首个元素相等,那么需要出栈,
            //出栈以后是要继续判断栈顶元素和popA的下一个元素是否相等的,
            //如果相等要继续出栈,不相等才进行下一轮的进栈,
            //所以这里需要的应该是一个循环来进行 多次的判断
            while(!stack.isEmpty() && stack.peek()==popA[j]){
                stack.pop();
                j++;
            }
        }
        return stack.isEmpty();
    }

5. 用两个栈实现队列【队列和栈】

牛客剑指offer题目

  • 思路:
    栈是先进后出,队列是先进先出。用两个栈实现队列的,入队和出队函数。
    入队,没什么好说的,就直接放入元素就可以了,也不需要返回值,所以直接存到stack1中记录即可。
    主要是出队的时候,注意是要先入队的先出,所以需要将元素从stack1中导入到stack2中,然后再tsack2出队,出队元素就是stack2中的顶级元素,这个元素是最先进入栈中的那个元素。
    还有一点需要注意的是,出队以后,方便其他元素下一次入队,是进入到stack1中,所以出队以后,需要将stack2中的元素再放回stack1中。

  • 代码:

//第5题:用两个栈实现队列
    Stack<Integer> stack1 = new Stack<Integer>();
    Stack<Integer> stack2 = new Stack<Integer>();

    public void push(int node) {
        stack1.push(node);  //入队,没什么好说的,就直接放入元素就可以了,也不需要返回值,所以直接存到stack1中即可
    }

    public int pop() {
        //主要是出队的时候,注意是要先入队的先出,所以需要将元素从stack1中导入到stack2中,然后再出队,出队元素就是stack2中的顶级元素
        //还有一点需要注意的是,出队以后,方便下一次入队,是进入到stack1中,所以出队以后,需要将stack2中的元素再放回stack1中
        while(!stack1.isEmpty()){
            stack2.push(stack1.pop());
        }
        int result= stack2.pop();
        while(!stack2.isEmpty()){
            stack1.push(stack2.pop());
        }
        return result;
    }
  • 知识点:
    补充用两个队列实现栈:
    压入元素,没什么好说的和栈的操作一样,先随便用一个队列存放压入的元素。
    出栈的时候,需要注意q1中入队1 2 3 出栈应该出3,所以我们一个一个出队,不是顶层的元素就出队之后存放到q2中。
    出掉3以后,再将q2中的元素存回q1中,方便下一次其他元素入队
//第5题补充,两个队列实现栈
    Queue<Integer> queue1=new LinkedList<>();
    Queue<Integer> queue2=new LinkedList<>();

    public void push(int node) {//压入元素,没什么好说的和栈的操作一样,先随便用一个队列存放压入的元素
        queue1.offer(node);
    }
    public int pop(){
        //出栈的时候,需要注意q1中入队1 2 3 出栈应该出3,所以我们一个一个出队,不是顶层的元素就出队之后存放到q2中,
        // 出掉3以后,再将q2中的元素存回q1中,方便下一次其他元素入队
        while (queue1.size()!=1){
            queue2.offer(queue1.poll());
        }
        int result=queue1.poll();
        while(!queue2.isEmpty()){
            queue1.offer(queue2.poll());
        }
        return result;
    }

也不确定代码错还是队,哪天遇到题验证一下吧。

你可能感兴趣的:(java学习,工作)