[Java实现]剑指offer21-25题_day5

21.栈的压入.弹出序列

题目描述

输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。(注意:这两个序列的长度是相等的)

思路:

借助一个辅助的栈,遍历压栈顺序,先将第一个放入栈中,这里是1,然后判断栈顶元素是不是出栈顺序的第一个元素,这里是4,1 != 4,所以继续压栈,直到相等以后开始出栈,出栈一个元素,则将出栈顺序向后移动一位,直到不相等,这样循环等压栈顺序遍历完成,如果辅助栈还不为空,说明弹出序列不是该栈的弹出顺序.

例如: 入栈: 1 , 2, 3 , 4 , 5 出栈: 4 , 5, 3, 2, 1
首先1入辅助栈,此时栈顶 1 != 4,继续入栈 2 ;
此时栈顶 2 != 4,继续入栈 3 ;
此时栈顶 3 != 4,继续入栈 4 ;
此时栈顶 4 = 4,出栈4,弹出序列向后一位,此时为5,辅助栈里的是1,2,3.
此时 3 != 5,继续入栈 5;
此时栈顶 5 = 5,出栈5,弹出序列向后一位,此时为3,辅助栈里面试1,2,3.

依次执行,最后辅助栈为空.如果不为空说明弹出序列不是该栈的弹出顺序.

package com.matajie;

import java.util.Stack;

/**
 * 21.栈的压入,弹出序列
 * 题目描述
 * 输入两个整数序列,第一个序列表示栈的压入顺序,
 * 请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。
 * 例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,
 * 但4,3,5,1,2就不可能是该压栈序列的弹出序列。(注意:这两个序列的长度是相等的)
 *
 * 我的程序才不会有bug!
 * author:年仅18岁的天才少年程序员丶mata杰
 **/
public class IsPopOrder {
    public boolean IsPopOrder(int [] pushA,int [] popA) {
      if(pushA.length == 0 || popA.length == 0){
          return false;
      }
        Stack<Integer> stack = new Stack<>();
      int popIndex = 0;//用于表示弹出序列的位置
      for(int i = 0;i<pushA.length;i++){
          stack.push(pushA[i]);
          while (!stack.empty() && stack.peek() == popA[popIndex]){//如果栈不为空,且栈顶元素等于弹出序列,出栈,弹出序列向后一位.
              stack.pop();
              popIndex++;
          }
      }
      return stack.empty();
    }
}

22.从上往下打印二叉树

题目描述

从上往下打印出二叉树的每个节点,同层节点从左至右打印。

思路:

用arrayList模拟一个队列来储存相应的TreeNode.

package com.matajie;

import java.util.ArrayList;

/**
 * 22从上往下打印二叉树
 * 题目描述
 * 从上往下打印出二叉树的每个节点,同层节点从左至右打印。
 *
 * 我的程序才不会有bug!
 * author:年仅18岁的天才少年程序员丶mata杰
 **/
public class PrintFromTopToBottom {
    public class TreeNode {
        int val = 0;
        TreeNode left = null;
        TreeNode right = null;

        public TreeNode(int val) {
            this.val = val;

        }

    }
    public ArrayList<Integer> PrintFromTopToBottom(TreeNode root) {
       ArrayList<Integer> list = new ArrayList<>();
       ArrayList<TreeNode> queue = new ArrayList<>();
       if(root == null){
           return list;
       }
       queue.add(root);
       while (queue.size() != 0){
           TreeNode temp = queue.remove(0);
           if(temp.left != null){
               queue.add(temp.left);
           }
           if(temp.right != null){
               queue.add(temp.right);
           }
           list.add(temp.val);
       }
       return list;
    }
}

23.二叉搜索树的后序遍历序列

题目描述

输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。

思路一:递归

在这里插入图片描述
如图:
中序序列为:2,5,9,12,15,16,17,18,19
后序序列为:2,9,5,16,17,15,19,18,12

如果按照后序遍历,先左后右自己的顺序来遍历树,数组的最后一个元素肯定是自己(父节点),然后剩余的部分分成两个部分,第一部分都比自己小(左子树部分),第二部分都比自己大(右子树部分),所以套用这个关系就可以循环检验处是否是二叉搜索树的后序遍历.

package com.matajie;

/**
 * 23.二叉搜索树的后序遍历序列
 * 题目描述
 * 输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。
 * 如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。
 *
 * 我的程序才不会有bug!
 * author:年仅18岁的天才少年程序员丶mata杰
 **/
public class VerifySquenceOfBST {
    public boolean VerifySquenceOfBST(int [] sequence) {
      if(sequence.length == 0) return false;
      if(sequence.length == 1) return true;
    return judge(sequence,0,sequence.length - 1);
    }
    public boolean judge(int[] a,int star,int root){
        if(star >= root) return true;
        int i = root;
        while (i>star && a[i-1] > a[root])
            i--;//找到比根小的坐标
        //从前面开始找,star到i-1应该比根小
        for(int j = star; j < i - 1;j++)
            if(a[j] > a[root]) return false;
        return judge(a, star, i -1 ) && judge(a, i ,root - 1);
    }
}

第一种全是右子树, i = start 调用最后的judge,左子树直接返回true, 右子树递归递归最后root - 1 = i = start , return true;
第二种全是左子树,i = root,调用最后的judge,左子树递归递归最后 root - 1 = start 返回true,右子树直接返回true;
第三种左右子树都有正常递归,继续直到进入前面两种情况之一.

思路2:非递归

左子树一定比右子树小,因此去掉根后,数字分为left,right两部分,right的部分最后一个数字是右子树的根也比左子树所有值大,所以我们可以每次只看有子树是否符合条件即可,即使到达了左子树,左子树也可以看出由左右子树组成的树还像右子树那样处理.对于左子树回到了原问题,对于右子树,左子树的所有值比右子树的跟小可以暂时把它看成右子树的左子树,只需看看右子树是否符合条件即可.

24.二叉树中和为某一值的路径

题目描述

输入一颗二叉树的跟节点和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。(注意: 在返回值的list中,数组长度大的数组靠前)

package com.matajie;

import java.util.ArrayList;

/**
 * 24.二叉树中和为某一值的路径
 * 题目描述
 *
 * 输入一颗二叉树的跟节点和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。
 * 路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成
 * 一条路径。(注意: 在返回值的list中,数组长度大的数组靠前)
 *
 * 我的程序才不会有bug!
 * author:年仅18岁的天才少年程序员丶mata杰
 **/
public class FindPath {
    public class TreeNode {
        int val = 0;
        TreeNode left = null;
        TreeNode right = null;

        public TreeNode(int val) {
            this.val = val;

        }

    }
    private ArrayList<ArrayList<Integer>> listAll = new ArrayList<ArrayList<Integer>>();
    private ArrayList<Integer> list = new ArrayList<>();
    public ArrayList<ArrayList<Integer>> FindPath(TreeNode root, int target) {
      if(root == null) return listAll;
      list.add(root.val);
      target -= root.val;
      if(target == 0 && root.left == null && root.right == null)
          listAll.add(new ArrayList<Integer>(list));//如果直接add(list),那么listAll的每一次add最终都指向用一个list对象
                                                    //也就是说,虽然当前保存的是对的list对象,但是之后这个
                                                    // list对象会被后续的递归修改,到最后的时候,得到的是空list,所以需要
                                                    //new一个list来保存当前对象的状态.
        FindPath(root.left,target);
        FindPath(root.right,target);
       list.remove(list.size()-1);//移除最后一个元素,深度遍历完一条路径要回退,递归到叶子节点如果没有找打路径,就要回退
                                        //到父节点继续寻找,依次类推.
       return listAll;
    }
}

25.复杂链表的复制

题目描述

输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的head。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)

思路:

  1. 遍历原链表的每一个节点,复制新节点,查到原链表的后边.
  2. 遍历原链表的每一个节点,进行新节点Random的设置.
  3. 把一条链表拆分为原链表和新链表.
package com.matajie;

/**
 * 25.复杂链表的复制
 * 题目描述
 * 输入一个复杂链表(每个节点中有节点值,以及两个指针,
 * 一个指向下一个节点,另一个特殊指针指向任意一个节点),
 * 返回结果为复制后复杂链表的head。
 * (注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)
 *
 * 我的程序才不会有bug!
 * author:年仅18岁的天才少年程序员丶mata杰
 **/
public class Clone {
    public class RandomListNode {
        int label;
        RandomListNode next = null;
        RandomListNode random = null;

        RandomListNode(int label) {
            this.label = label;
        }
    }
    public RandomListNode Clone(RandomListNode pHead)
    {
        if(pHead == null)return null;
       RandomListNode cur = pHead;
       //1.插入
       while (cur != null){
           RandomListNode newNode = new RandomListNode(cur.label);
           newNode.next = cur.next;//把newNode插到cur后
           cur.next = newNode;
           cur = cur.next.next;//让cur走向下一个原链表的节点
       }
       //2.设置
        cur = pHead;
       while (cur != null){
           RandomListNode newNode = cur.next;
           if(cur.random == null){
               newNode.random = null;
           }else {
               newNode.random = cur.random.next;
           }
           cur = cur.next.next;
       }
       //3.拆分
        cur = pHead;
       RandomListNode result = pHead.next;
       while (cur != null){
           RandomListNode newNode = cur.next;
           cur.next = newNode.next;
           if(newNode.next != null){
               newNode.next = newNode.next.next;
           }
           cur = cur.next;//不再是cur.next.next,因为已经拆分
       }
       return result;
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值