剑指offer 21到30题(JAVA)

第二十一题:

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

思路:

  • 一个弹出序列,一个压栈序列,弹出序列中的数,比如第一个弹出·的数,肯定是在压栈过程中弹出来的,所以在这里新建一个栈stack,如果压栈序列中要压入的数和弹出序列当前的数不一样(说明没找到),那么压栈序列继续压,直到压栈序列中找到了和弹出序列当前下标值相等的数,那么弹出序列的下标值就+1,。

  • 结束条件就是弹出序列的下标值可以到达序列的末尾。

 代码:

import java.util.*;

public class Solution {
    public boolean IsPopOrder(int [] pushA,int [] popA) {
      if(pushA.length!=popA.length)
          return false;
        Stack<Integer> stack1=new Stack<>(); //栈记录压栈
        int j=1;
        stack1.push(pushA[0]);//栈中先压入push压栈序列的第一个数
        for(int i=0;i<popA.length;i++)
        {
          while(j<pushA.length&&stack1.peek()!=popA[i])
          {//如果栈顶的数和弹出的序列不一样,就一直压栈,因为必须是从栈顶弹出的
            stack1.push(pushA[j]);
            j++;
            }
            if(j>=pushA.length&&stack1.peek()!=popA[i])
                return false;//如果j已经到达压栈序列的末尾,但是栈顶的数还是和弹出的序列不一样。
        //说明没这个序列
        stack1.pop();//如果j<=push.length&&stack1.peek()=popA[i],那么就出栈
    }
    return true;
}
}

---------------------------------------------------------------可爱的分界线----------------------------------------------------------------------------------------

第二十二题:

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

思路:
使用一个队列,实现二叉树的层次遍历

代码:

import java.util.*;
/**
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

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

    }

}
*/
public class Solution {
    public ArrayList<Integer> PrintFromTopToBottom(TreeNode root) {
        ArrayList<Integer>resultList=new ArrayList<>();
        if(root==null)
        {
            return  resultList;
        }
        Queue<TreeNode> queue=new LinkedList<>();
        queue.offer(root);
        while(queue.size()!=0)//队列不为空一直进行
        {
            TreeNode tempRoot=queue.poll();//出队,同时赋值新的tempRoot
            if(tempRoot.left!=null)//左子节点不为空,左子节点入队
            queue.offer(tempRoot.left);
            if(tempRoot.right!=null)//右子节点不为空,右子节点入队
                queue.offer(tempRoot.right);
            resultList.add(tempRoot.val);//把出队的节点的值保留下来
        }
        return resultList;
    }
}

---------------------------------------------------------------可爱的分界线----------------------------------------------------------------------------------------

第二十三题:

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

思路:递归的思想,后序遍历,根都为数组的最后一位,根据左子树的值都必须大于根结点,右子树的值都必须小于根结点,划分左右子树,然后各自进入递归,过程中,一旦右子树的值大于根结点,直接返回flase,最后返回true。(过程中用标记实现)

代码:

import java.util.Arrays;
public class Solution {
    public boolean VerifySquenceOfBST(int [] sequence) {
			if(sequence==null||sequence.length<=0){
				return false;
			}
			int len=sequence.length;
			int root=sequence[len-1];
			int i=0;
			for(;i<len-1;i++){
				if(root<=sequence[i])
					break;
			}
			int j=i;//找到划分左子树和右子树的点
			for(;j<len-1;j++){
				if(root>sequence[j]){
					return false;//如果根大于右子树的结点
				}
			}
			boolean leftFlag=true;
			if (i>0) {
			leftFlag=VerifySquenceOfBST(Arrays.copyOfRange(sequence,0,i));//复制并递归左子树
		     //copyOfRange方法是一个静态方法,这个将指定数组的指定范围复制到新数组中。(左闭右开)
            }
			boolean rightFlag=true;
			if (i<len-1) {
			rightFlag=VerifySquenceOfBST(Arrays.copyOfRange(sequence,i,sequence.length-1));
                //复制并递归右子树
			}
			return leftFlag&&rightFlag;
	    }
 
}

---------------------------------------------------------------可爱的分界线----------------------------------------------------------------------------------------

第二十四题:

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

思路:
递归的思路,如果和为整数,则记录路径到一个list中,否则递归左子树,右子树,如果都不满足,那么回退父节点

代码:

import java.util.ArrayList;
/**
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;
    public TreeNode(int val) {
        this.val = val;
    }
}
*/
public class Solution {
    ArrayList<ArrayList<Integer>> pathList = new ArrayList<ArrayList<Integer>>();
    ArrayList<Integer> path = new ArrayList<Integer>();
    public ArrayList<ArrayList<Integer>> FindPath(TreeNode root,int target) {
          if(root == null)
              return  pathList; 
          path.add(root.val);//加入根结点的值
          if(root.left == null && root.right == null && target == root.val)
          {
                pathList.add(new ArrayList<Integer>(path));//加入路径pathLsit
          }
          if(root.val <target && root.left != null){
              FindPath(root.left,target-root.val); //递归左孩子
          }  
          if(root.val <target && root.right != null)
          {
              FindPath(root.right,target-root.val); //递归右孩子
          }   
          path.remove(path.size()-1);//其余情况,则回退到父节点
          return pathList;
    }
}

---------------------------------------------------------------可爱的分界线----------------------------------------------------------------------------------------

第二十五题

(参考:https://blog.csdn.net/qq_41901915/article/details/90286802):

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

思路:

第一步,在原节点后面创建一个相同的节点,其实就是链表插入的过程

第二步,遍历克隆的节点,让它的random等于原来的随机的next,也就是下一个节点

第三步,遍历整个克隆完毕的链表,让当前点指向下面隔一个的点

代码:

/*
public class RandomListNode {
    int label;
    RandomListNode next = null;
    RandomListNode random = null;
    RandomListNode(int label) {
        this.label = label;
    }
}
*/
public class Solution {
    public RandomListNode Clone(RandomListNode pHead) {
        if(pHead == null) {
            return null;
        }
         
        RandomListNode currentNode = pHead;
        //1、复制每个结点,如复制结点A得到A1,将结点A1插到结点A后面;
        while(currentNode != null){
            RandomListNode cloneNode = new RandomListNode(currentNode.label);
            RandomListNode nextNode = currentNode.next;//先保存currentNode.next
            currentNode.next = cloneNode;//令currentNode.next=cloneNode
            cloneNode.next = nextNode;//将之前的currentNode.next赋给cloneNode.next
            currentNode = nextNode;//指针向后移
        }
        currentNode = pHead;//指针回到开头
        //2、重新遍历链表,复制老结点的随机指针给新结点,如A1.random = A.random.next;
        while(currentNode != null) {
            currentNode.next.random = currentNode.random==null?null:currentNode.random.next;
            currentNode = currentNode.next.next;
        }
        //3、拆分链表,将链表拆分为原链表和复制后的链表
        currentNode = pHead;//指正回到开头
        RandomListNode pCloneHead = pHead.next;//克隆的链表指向A1
        while(currentNode != null) {
            RandomListNode cloneNode = currentNode.next;//先保存cloneNode
            currentNode.next = cloneNode.next;//将A和B连接在一起
            //将A和A1连接在一起
            cloneNode.next = cloneNode.next==null?null:cloneNode.next.next;
            currentNode = currentNode.next;//指正向后移到B
        }
        return pCloneHead;
    }
}

 

---------------------------------------------------------------可爱的分界线----------------------------------------------------------------------------------------

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值