剑指offer面试题(21-30)——java实现

面试题21:包含min函数的栈

定义栈的数据结构,请在该类型中实现一个能够得到栈的最小元素的min函数。

思路:使用辅助栈保存栈中的最小元素在栈顶

import java.util.Stack;

public class ContainMinFuncStack extends Stack {
    private static Stack helpStack = new Stack();

    public int push(int item) {
//        添加数据到数据栈
        addElement(item);
        if (helpStack.empty() || item < (int)(helpStack.peek())){
            helpStack.push(item);
        }else {
            helpStack.push(helpStack.peek());
        }
        return item;
    }

    public Object pop(){
        helpStack.pop();
        return super.pop();
    }

    public int getMinNumberFromStack(){
        if (helpStack.empty()) return (int) super.peek();
        return (int) helpStack.peek();
    }

    public static void main(String[] args) {
        ContainMinFuncStack stack = new ContainMinFuncStack();
        stack.push(3);
        System.out.println(stack.getMinNumberFromStack());
        stack.push(4);
        System.out.println(stack.getMinNumberFromStack());
        stack.push(2);
        System.out.println(stack.getMinNumberFromStack());
        stack.push(1);
        System.out.println(stack.getMinNumberFromStack());
        stack.pop();
        System.out.println(stack.getMinNumberFromStack());
    }
}

面试题22:栈的压入、弹出序列

输入两个整数序列,第一个表示栈的压入序列,判断第二个序列是否是栈的弹出序列,假设压入栈的所有数字均不相等

思路:使用辅助栈

import java.util.Stack;

public class PushIsEqualPop {
    public static boolean pushIsEqualPop(int[] push,int[] pop) throws Exception {
        int lenPush = push.length;
        int lenPop = pop.length;
        if (lenPop == 0 || lenPush == 0 || lenPop != lenPush) throw new Exception("非法输入!");
        int i = 0, j = 0;
        Stack<Integer> temp = new Stack();
        while (i < lenPush && j < lenPop){
            if (push[i] != pop[j]) {
                temp.push(push[i]);
                i++;
            }else {
                i++;
                j++;
            }
        }
        while (!temp.empty()){
            if (temp.pop() != pop[j]) return false;
            else j++;
        }
        return true;
    }

    public static void main(String[] args) {
        int[] push = {1,2,3,4,5};
        int[] pop = {4,5,3,2,1};
        int[] pop2 = {4,3,5,1,2};
        try {
            System.out.println(pushIsEqualPop(push,pop));
            System.out.println(pushIsEqualPop(push,pop2));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

面试题23:从上往下打印二叉树

思路:利用队列保存节点,以及它的左右孩子,队列依次出队并打印该节点和其左右孩子

import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;

public class BreadthFirstTraversal {
    public static void breadthFirstTraversal(Node tree){
        if (tree == null) return;
        Queue<Node> queue = new ConcurrentLinkedQueue<>();
        queue.add(tree);
        while (!queue.isEmpty()){
            Node node = queue.poll();
            System.out.println(node.value);
            if (node.left != null) queue.add(node.left);
            if (node.right != null) queue.add(node.right);
        }
    }

    public static void main(String[] args) {
        Node node = new Node(8);
        Node node1 = new Node(8);
        Node node2 = new Node(7);
        Node node3 = new Node(9);
        Node node4 = new Node(2);
        Node node5 = new Node(4);
        Node node6 = new Node(7);
        node.left = node1;
        node.right = node2;
        node1.left = node3;
        node1.right = node4;
        node4.left = node5;
        node4.right = node6;
        breadthFirstTraversal(node);
    }
}

面试题24:二叉搜索树的后序遍历

输入一个整数数组,判断该数组是不是某一个二叉搜索树的后序遍历的结果
假设输入的数组的任何一个数字都不相同

思路:在后序遍历的结果中,最后一个总是根节点,前面比它小的数字就是左子树,后面比它大的就是右子树,然后相同的规律,可以使用递归

 public class BSTPostOrder {
    public static boolean isBSTPostOrder(int[] array,int start,int end) throws Exception {
        if (array == null || end < 0) return false;
        int root = array[end];
        int i = 0;
        for (; i < end; i++){
            if (array[i] > root) break;
        }
        int j = i;
        for (; j < end; j++){
            if (array[j] < root) return false;
        }
        boolean left = true;
//        判断左子树,i = 0时没有左子树
        if (i > 0){
            left = isBSTPostOrder(array,start,i - 1);
        }
//        判断右子树,i = end时没有右子树
        boolean right = true;
        if ( i < end){
            right = isBSTPostOrder(array,i,end - 1);
        }
        return (left && right);
    }

    public static void main(String[] args) {
        int[] array1 = {5,7,6,9,11,10,8};
        int[] array2= {7,4,6,5};
        try {
            System.out.println(isBSTPostOrder(array1,0,6));
            System.out.println(isBSTPostOrder(array2,0,3));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

面试题25:二叉树中和为某一值n的路径

二叉树中从树的根节点开始往下一直到叶节点所经过的节点形成一条路径

思路:借助辅助栈,使用一个数记录每个入栈节点的和
首先将根节点入栈,判断该节点是否是叶节点:
1.如果不是则用记录数记录和并入栈,接着访问左节点或右节点
2.如果是则判断记录数是否和n相同:
(1)相同的话则该栈就是符合条件的一条路径
(2)如果不相同,弹出栈顶元素,继续访问其右节点

import java.util.Vector;

public class SumIsNDePath {
    public static void findThePathSumIsN(Node tree, int number){
        if (tree == null) return;
        Vector<Node> helpStack = new Vector<>();
        int current = 0;
        findThePathSumIsN(tree,number,helpStack,current);
    }

    private static void findThePathSumIsN(Node tree, int number, Vector<Node> helpStack, int current) {
        current += tree.value;
        helpStack.add(tree);

        if (tree.left == null && tree.right == null && current == number){
            System.out.println("找到了一条路径:");
            for (int i = 0; i < helpStack.size(); i++){
                System.out.println((helpStack.get(i)).value);
            }
        }
        if (tree.left != null) findThePathSumIsN(tree.left, number, helpStack , current);
        if (tree.right != null) findThePathSumIsN(tree.right, number, helpStack , current);

        if (!helpStack.isEmpty()) helpStack.removeElementAt(helpStack.size() - 1);
    }

    public static void main(String[] args) {
        Node node = new Node(10);
        Node node1 = new Node(5);
        Node node2 = new Node(12);
        Node node3 = new Node(4);
        Node node4 = new Node(7);
        node.left = node1;
        node.right = node2;
        node1.left = node3;
        node1.right = node4;
        findThePathSumIsN(node,19);
    }
}

面试题26:复杂链表的复制

在这里插入图片描述

class ComplexNode{
    int value;
    ComplexNode next;
    ComplexNode siblig;

    public ComplexNode() {
    }

    public ComplexNode(int value) {
        this.value = value;
    }

}
public class CopyComplexList {
    public static ComplexNode copy(ComplexNode sourceNode){
        if (sourceNode == null) return sourceNode;
        copyNext(sourceNode);
        copySibling(sourceNode);
        return getCopyList(sourceNode);
    }

    public static void copyNext(ComplexNode sourceNode){
        ComplexNode current = sourceNode;
        while (current != null){
            ComplexNode cloneNode = new ComplexNode();
            cloneNode.value = current.value;
            cloneNode.next = current.next;
            cloneNode.siblig = null;
            current.next = cloneNode;
            current = cloneNode.next;
        }
    }

    public static void copySibling(ComplexNode sourceNode){
        ComplexNode current = sourceNode;
        while (current != null){
            ComplexNode cloneNode = current.next;
            if (current.siblig != null){
                cloneNode.siblig = current.siblig.next;
            }
            current = cloneNode.next;
        }
    }

    public static ComplexNode getCopyList(ComplexNode sourceNode){
        ComplexNode current = sourceNode;
        ComplexNode cloneNodeHead = null;
        ComplexNode cloneNodeCurrent = null;
        if (current != null){
            cloneNodeHead = cloneNodeCurrent = current.next;
            current.next = cloneNodeCurrent.next;
            current = current.next;
        }
        while (current != null){
            cloneNodeCurrent.next = current.next;
            cloneNodeCurrent = cloneNodeCurrent.next;
            current.next = cloneNodeCurrent.next;
            current = current.next;
        }
        return cloneNodeHead;
    }

    public static void main(String[] args) {
        ComplexNode complexNode1 = new ComplexNode(1);
        ComplexNode complexNode2 = new ComplexNode(2);
        ComplexNode complexNode3 = new ComplexNode(3);
        ComplexNode complexNode4 = new ComplexNode(4);
        ComplexNode complexNode5 = new ComplexNode(5);
        complexNode1.next = complexNode2;
        complexNode2.next = complexNode3;
        complexNode3.next = complexNode4;
        complexNode4.next = complexNode5;
        complexNode1.siblig = complexNode3;
        complexNode2.siblig = complexNode5;
        complexNode4.siblig = complexNode2;
        ComplexNode complexNode = copy(complexNode1);
        while (complexNode != null){
            System.out.println("节点" + complexNode.value);
            if (complexNode.next != null){
                System.out.println("next:" + complexNode.next.value);
            }
            if (complexNode.siblig != null){
                System.out.println("sibling:" + complexNode.siblig.value);
            }
            complexNode = complexNode.next;
        }
    }
}

面试题27:二叉搜索树与双向链表

在这里插入图片描述

将二叉搜索树转换成双向链表不能新建新的节点,只能调整树中的节点

思路:上图可以看出双向链表是二叉树中序遍历的结果,将根节点如下图处理,使用递归可以解决
在这里插入图片描述

public class BinaryTreeToList {
    public static Node toList(Node tree){
        Node lastNodeInList = null;//指向链表中的最后一个节点

//        返回头结点
        Node head = convertToList(tree,lastNodeInList);
        while (head != null && head.left != null){
            head = head.left;
        }
        return head;
    }

    private static Node convertToList(Node tree, Node lastNodeInList) {
        if (tree == null) return lastNodeInList;
        Node current = tree;
        if (current.left != null) lastNodeInList = convertToList(current.left, lastNodeInList);
        current.left = lastNodeInList;
        if (lastNodeInList != null) lastNodeInList.right = current;
        lastNodeInList = current;
        if (current.right != null) lastNodeInList = convertToList(current.right, lastNodeInList);
        return lastNodeInList;
    }

    public static void main(String[] args) {
        Node node = new Node(10);
        Node node1 = new Node(5);
        Node node2 = new Node(12);
        Node node3 = new Node(4);
        Node node4 = new Node(7);
        node.left = node1;
        node.right = node2;
        node1.left = node3;
        node1.right = node4;
        Node list = toList(node);
        while (list != null){
            System.out.println("value:" + list.value);
            list = list.right;
        }
    }
}

面试题28:字符串的排列

输入一个字符串,打印出该字符中所有字符串中字符的所有排列。

思路:分成一个和后面两部分,无非两种情况,一个在前一个在后

import java.util.ArrayList;
import java.util.TreeSet;

public class StringArrange {
    public static ArrayList<String> getStringArrange(String str){
        ArrayList<String> result = new ArrayList<>();
        if (str == null || str.length() == 0) return null;
        char[] chars = str.toCharArray();
        TreeSet<String> tempRes = new TreeSet<>();
        PermutationCore(chars,tempRes,0);
        result.addAll(tempRes);
        return result;
    }

    private static void PermutationCore(char[] chars, TreeSet<String> tempRes, int loc) {
        if (chars == null || chars.length == 0 || loc < 0 || loc > chars.length - 1) return;
        if (loc == chars.length - 1){
            tempRes.add(String.valueOf(chars));
        }else {
            for (int i = loc; i < chars.length; i++){
                swap(chars,i,loc);
                PermutationCore(chars,tempRes,loc + 1);
                swap(chars,i,loc);
            } 
        }
    }
    private static void swap(char[] charArray,int i,int j)
    {
        char temp = charArray[i];
        charArray[i] = charArray[j];
        charArray[j] = temp;
    }
    public static void main(String[] args) {
        ArrayList<String> arrayList = getStringArrange("abc");
        for (int i = 0; i < arrayList.size(); i++){
            System.out.println(arrayList.get(i));
        }
    }
}

面试题29:数组中出现次数超过一半的数字

数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字

思路:用两个数,一个记录数字中的数,一个记录出现的次数,首先将数字赋值为数组的首元素,次数赋值为1,如果下一个和当前数字相同则次数加一,如果数字不同,则次数减一,当次数减为零时,将当前数字变为使次数为0的数字

public class MoreThanHalf {
    public static int getNumberMoreThanHalf(int[] array){
        if (array == null || array.length == 0) return 0;
        int result = array[0],count = 1;
        for (int i = 1; i < array.length; i++){
            if (result == array[i]){
                count++;
            }else {
                count--;
                if (count == 0){
                    result = array[i];
                    count++;
                }
            }
        }
        count = 0;
        for (int i = 0; i < array.length; i++){
            if (array[i] == result){
                count++;
            }
        }
        if ((count << 1) < array.length) return 0;
        return result;
    }

    public static void main(String[] args) {
        int[] array = {1,2,3,2,2,2};
        System.out.println(getNumberMoreThanHalf(array));
    }
}

面试题30:最小的k个数

在数组中找到其中最小的k个数

思路:排序后自然可取,但是有更好的方法,基于快速排序

public class KSmallestNumber {
    public static void getKSmallestNumbers(int[] array,int k){
        if (array == null || array.length == 0 || k > array.length || k == 0) return;
        int start = 0,end = array.length - 1;
        int index = partion(array,start,end);
        while (index != k - 1){
            if (index > k - 1){
                end = index - 1;
                index = partion(array,start,end);
            }else {
                start = index + 1;
                index = partion(array,start,end);
            }
        }
        for (int i = 0; i < k; i++){
            System.out.println(array[i]);
        }
    }

    private static int partion(int[] array, int start, int end) {
        int target = array[start];
        while (start < end){
            while (start < end && array[end] >= target) end--;
            array[start] = array[end];
            while (start < end && array[start] <= target) start++;
            array[end] = array[start];
            array[start] = target;
        }
        return start;
    }

    public static void main(String[] args) {
        int[] array = {4,5,1,6,2,7,3,8};
        getKSmallestNumbers(array,0);
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值