leetcode算法题-剑指Offer篇(2)

leetcode算法题-剑指Offer篇(2)

1、 从尾到头打印链表

1.1 题目描述:

输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回)。

1.2 题解
1.2.1 创建数组保存链表节点值,对数组进行反转;
   public int[] reversePrint(ListNode head) {
        if(head==null)
            return new int[0];//如果头结点为空,返回空数组
        ListNode index =head;
        ArrayList<Integer> list=new ArrayList<>();
        while(index!=null){//正向保存节点值
          list.add(index.val);
          index=index.next;
        }
        int length=list.size();
        int[] result =new int[length];
        for(int i=0;i<length;i++){//逆向保存节点值
            result[i]=list.get(length-i-1);
        }
        return result;
    }
1.2.2 利用栈的后进先出的性质,来保存节点值,在一一弹出;
 public int[] reversePrint(ListNode head) {
        Stack<ListNode> stack = new Stack<ListNode>();
        ListNode temp = head;
        while (temp != null) {//将节点一一保存到栈中
            stack.push(temp);
            temp = temp.next;
        }
        int size = stack.size();
        int[] print = new int[size];
        for (int i = 0; i < size; i++) {//从栈中一一得出节点值
            print[i] = stack.pop().val;
        }
        return print;
    }

2、重建二叉树

2.1 题目描述:

输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。

2.2 题解
2.2.1 利用前序遍历和中序遍历的性质

前序遍历的顺序是父节点、左子节点、右子节点;中序遍历的顺序是,左子节点、父节点、右子节点
前序遍历第一个是根节点,由于数字不重复,因此找到中序遍历中等于根节点的值,则此节点的左侧为左子树,右侧为右子树
;以此类推,直到找到前中后序的最后一位;

  public TreeNode buildTree(int[] preorder, int[] inorder) {
        if (preorder.length == 0 || preorder == null)
            return null;
        Map<Integer, Integer> indexMap = new HashMap<Integer, Integer>();//保存中序遍历的每个元素及其对应的下标
        int length=preorder.length;
        for (int i = 0; i < length; i++) {
            indexMap.put(inorder[i], i);
        }
        TreeNode root = helpBuildTree(preorder, 0, length - 1, inorder, 0, length - 1, indexMap);
        return root;
    }

    /**
     *
     * @param preorder 前序遍历
     * @param preorderStart 前序遍历开始位置
     * @param preorderEnd 前序遍历终止位置
     * @param inorder  中序遍历
     * @param inorderStart 开始位置
     * @param inorderEnd 终止位置
     * @param indexMap  保存中序遍历的每个元素及其对应的下标
     * @return
     */
    public TreeNode helpBuildTree(int[] preorder, int preorderStart, int preorderEnd, int[] inorder, int inorderStart, int inorderEnd, Map<Integer, Integer> indexMap) {
        if (preorderStart > preorderEnd) {
            return null;
        }
        int rootVal = preorder[preorderStart];
        TreeNode root = new TreeNode(rootVal);
        if(preorderStart == preorderEnd)    
            return root;
        else {
            int rootIndex = indexMap.get(rootVal);//从map中取出相应值在中序遍历中的下标
            int leftNodes = rootIndex - inorderStart, rightNodes = inorderEnd - rootIndex;//父节点的左右分别为左右子树
            TreeNode leftSubtree = helpBuildTree(preorder, preorderStart + 1, preorderStart + leftNodes, inorder, inorderStart, rootIndex - 1, indexMap);
            TreeNode rightSubtree = helpBuildTree(preorder, preorderEnd - rightNodes + 1, preorderEnd, inorder, rootIndex + 1, inorderEnd, indexMap);
            root.left = leftSubtree;
            root.right = rightSubtree;
            return root;

        }
    }

3、用两个栈实现队列

3.1 题目描述:

用两个栈实现一个队列。队列的声明如下,请实现它的两个函数 appendTail 和 deleteHead ,分别完成在队列尾部插入整数和在队列头部删除整数的功能。(若队列中没有元素,deleteHead 操作返回 -1 )

3.2 题解
3.2.1
Stack<Integer> appendStack;//放入用
    Stack<Integer> deleteStack;//取出用
    public CQueue() {
        appendStack=new Stack<>();
        deleteStack=new Stack<>();
    }

    public void appendTail(int value) {
        appendStack.push(value);
    }

    public int deleteHead() {
        if(deleteStack.empty()&&appendStack.empty())
            return -1;
        else {
            if(deleteStack.empty()){
                while(!appendStack.empty())
                    deleteStack.push(appendStack.pop());//将放入的值存放到取出用栈,因为栈的后进先出,这样能保证取出顺序
                return deleteStack.pop();
            }
            else {
                return deleteStack.pop();
            }
        }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值