第四章

    /**
     * 面试题27 输入一颗二叉树,输出一颗对称的二叉树
     * 思路:从根结点开始,交换两个子结点
     *
     * @param root
     */
    public void mirror(TreeNode root) {
        if (root == null) return;
        TreeNode temp = root.left;
        root.left = root.right;
        root.right = temp;
        mirror(root.left);
        mirror(root.right);
    }
    /**
     * 面试题28:判断输入二叉树是否是对称二叉树
     * 思路:将前序遍历和前序对称遍历获取的结点值进行比较
     *
     * @param root
     * @return
     */
    public boolean isSym(TreeNode root) {
        //invalid input
        if (root == null) return false;
        return isSymCore(root, root);
    }

    private boolean isSymCore(TreeNode root1, TreeNode root2) {
        //递归结束条件
        if (root1 == null && root2 == null) return true;
        if (root1 == null || root2 == null) return false;
        if (root1.val != root2.val) return false;
        //root1 and root2 是对称遍历
        return isSymCore(root1.left, root2.right) && isSymCore(root1.right, root2.left);
    }
    /**
     * 面试题30:含有O(1)min方法的栈
     * 思路:建立一个辅助栈,该栈中栈顶元素始终是当前数据栈中的最小元素。
     */
    private Stack<Integer> dateStack = new Stack<>();
    private Stack<Integer> minStack = new Stack<>();

    public void push(int date) {
        //入栈的数据是当前最小值,注意minStack为空的情况
        if (date < minStack.peek() || minStack.empty()) {
            minStack.push(date);
        } else minStack.push(minStack.peek());
        dateStack.push(date);
    }

    public int pop() {
        minStack.pop();//栈为空时抛出异常
        return dateStack.pop();
    }

    public int min() {
        return minStack.peek();
    }
    /**
     * 面试题31:判断压入栈和弹出栈是否匹配
     * 思路:建立一个辅助栈
     * 当辅助栈顶元素值为空,或者与出栈序列不同时,入栈序列入栈
     * 相同时,出栈序列出栈,辅助栈出栈
     *
     * @param pushA
     * @param popA
     * @return
     */
    public boolean IsPopOrder(int[] pushA, int[] popA) {
        //invalid input
        if (pushA == null || popA == null) return false;
        int pushALen = pushA.length;
        int popALen = popA.length;
        if (pushALen != popALen) return false;
        //匹配
        int pushAptr = 0;
        int popAptr = 0;
        Stack<Integer> stack = new Stack<>();
        while (popAptr != popALen) {
            if (stack.empty() || stack.peek() != popA[popAptr]) {
                if (pushAptr == pushALen) return false;
                else stack.push(pushA[pushAptr++]);
            } else {
                stack.pop();
                ++popAptr;
            }
        }
        return true;
    }
    /**
     * 面试题32: 从上到下打印二叉树
     * 思路:用队列保存下一层要打印的结点
     * 从队列中出一个结点,打印后将该结点的左右子结点加入队列中,直到队列为空结束
     * <p>
     * 面试题32(题目二): 从上到下分行打印二叉树
     * 思路:在队列中添加分行标志位
     *
     * @param root
     * @return
     */
    public ArrayList<Integer> PrintFromTopToBottom(TreeNode root) {
        ArrayList<Integer> result = new ArrayList<>(); //save result
        //invalid input
        if (root == null) return result;
        LinkedList<TreeNode> queue = new LinkedList<>();//assist queue
        queue.offer(root);
        while (!queue.isEmpty()) {
            TreeNode temp = queue.poll();
            result.add(temp.val);
            if (temp.left != null)
                queue.offer(temp.left);
            if (temp.right != null)
                queue.offer(temp.right);
        }
        return result;
    }
    /**
     * 面试题33:判断数组是否为搜索二叉树的后序遍历序列
     * 思路:
     * 1 数组最后一个元素为该树的根节点
     * 2 根据该根节点将数组前面的元素划分为左子树部分和右子树部分
     * 3 递归调用,判断是否是后序遍历
     *
     * @param sequence
     * @return
     */
    public boolean VerifySquenceOfBST(int[] sequence) {
        //invalid input
        if (sequence == null) return false;
        int length = sequence.length;
        if (length == 0) return false;
        return VerifySquenceOfBSTCore(sequence, 0, length - 1);
    }

    private boolean VerifySquenceOfBSTCore(int[] sequence, int lo, int hi) {
        if (lo < 0 || hi < 0 || lo >= hi) return true;
        int rootVal = sequence[hi]; //根结点值
        int leftroot = -1;
        int rightroot = -1;
        if (sequence[lo] < rootVal) leftroot = lo;
        int i = -1;//迭代变量
        for (i = lo; i < hi; i++) { //找第一个大于根节点的值
            if (sequence[i] > rootVal) {
                rightroot = i;
                break;
            }
        }
        for (i = i + 1; i < hi; i++) {//判断后面的元素是否均大于根结点值
            if (sequence[i] <= rootVal)
                return false;
        }
        return VerifySquenceOfBSTCore(sequence, leftroot, rightroot - 1) &&
                VerifySquenceOfBSTCore(sequence, rightroot, hi - 1);
    }
    /**
     * 面试题34:二叉树中和为某一值的路径
     * 技巧,可以用三层树型结构来代测试
     * 思路:
     * 1 递归的寻找路径,在遍历过程中记录经过的路劲
     * 2 递归到叶结点时判断该路径是否符合条件,并添加到结果数组中
     *
     * @param root
     * @param target
     * @return
     */
    public ArrayList<ArrayList<Integer>> FindPath(TreeNode root, int target) {
        ArrayList<ArrayList<Integer>> result = new ArrayList<ArrayList<Integer>>();
        if (root == null) return result;
        ArrayList<Integer> path = new ArrayList<>();
        findPath(root, target, path, result);
        return result;
    }

    private void findPath(TreeNode root, int target, ArrayList<Integer> path, ArrayList<ArrayList<Integer>> result) {
        if (root == null) return;
        if (root.left == null && root.right == null) { //叶结点
            path.add(root.val);
            if (root.val == target)
                result.add(new ArrayList<Integer>(path));
            path.remove(path.size() - 1);
            return;
        }
        path.add(root.val);
        findPath(root.left, target - root.val, path, result);
        findPath(root.right, target - root.val, path, result);
        path.remove(path.size() - 1);
    }
    /**
     * 面试题35:复杂链表的复制
     * 思路:
     * 1 在更复杂链表中插入相同的结点
     * 2 连接自由结点
     * 3 分离两条链表
     *
     * @param pHead
     * @return
     */
    public RandomListNode Clone(RandomListNode pHead) {
        if (pHead == null) return null;
        //     * 1 在更复杂链表中插入相同的结点
        RandomListNode copyNode = pHead;
        while (copyNode != null) {
            RandomListNode node = new RandomListNode(copyNode.label);
            node.next = copyNode.next;
            copyNode.next = node;
            copyNode = copyNode.next.next;
        }
        //     * 2 连接自由结点
        copyNode = pHead;
        while (copyNode != null) {
            copyNode.next.random = copyNode.random == null ? null : copyNode.random.next;
            copyNode = copyNode.next.next;
        }
        //     * 3 分离两条链表
        copyNode = pHead;
        RandomListNode node = pHead.next;
        RandomListNode result = pHead.next;
        while (copyNode.next.next != null) {
            copyNode.next = copyNode.next.next;
            node.next = node.next.next;
            copyNode = copyNode.next;
            node = node.next;
        }
        copyNode.next = null; //容易忽视
        return result;
    }
    /**
     * 面试题36:将二叉搜索树转化成一个排序的双向链表
     * 思路
     * 1 中序遍历递归地构造双向链表,并返回双向链表的尾部
     *
     * @param pRootOfTree
     * @return
     */
    private TreeNode tail = null; //链表的尾部
    private TreeNode head = null; //链表的头部

    public TreeNode Convert(TreeNode pRootOfTree) {
        ConvertCore(pRootOfTree);
        return head;
    }

    private void ConvertCore(TreeNode node) {
        if (node == null) return;
        ConvertCore(node.left);
        if (tail == null) {
            tail = node;
            head = node;
        } else {
            tail.right = node;
            node.left = tail;
            tail = node;
        }
        ConvertCore(node.right);
    }
    /**
     * 面试题38:打印输入字符串的所有排列
     *  递归法,问题转换为先固定第一个字符,求剩余字符的排列;求剩余字符排列时跟原问题一样。
     * (1) 遍历出所有可能出现在第一个位置的字符(即:依次将第一个字符同后面所有字符交换);
     * (2) 固定第一个字符,求后面字符的排列(即:在第1步的遍历过程中,插入递归进行实现)。
     * 需要注意的几点:
     * (1) 先确定递归结束的条件;
     * (2) 去重复;
     * (3) 按字典顺序排列;
     * @param str
     * @return
     */
    public ArrayList<String> Permutation(String str) {
        char[] strArr = str.toCharArray();
        ArrayList<String> result = new ArrayList<>();
        if(str==null||str.length()==0) return result;
        Set<String> res = new TreeSet<>(); //利用TreeSet集合类来实现去重复和排序
        Permutation(strArr, 0, res);
        result.addAll(res);
        return result;
    }

    private void Permutation(char[] strArr, int index,  Set<String> result) {
        if (index == strArr.length) {
            result.add(new String(strArr));
            return;
        }
        for (int i = index; i < strArr.length; i++) {
            exch(strArr, index, i); //确定一个位置的字符
            Permutation(strArr, index + 1, result);
            exch(strArr, index, i);
        }
    }

    private void exch(char[] arr, int i, int j) {
        char temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
原文地址:https://www.cnblogs.com/youzoulalala/p/11337690.html