JAVA实现 剑指offer 第二版 3

面试题27_1:二叉树的镜像

遍历,若节点存在子节点,交换二叉树的左右节点;循环的方式也是和遍历一样,可以采用栈进行暂存;
 public static void MirrorRecursively(Node head){
        if (head == null){
            return;
        }
        if (head.left == null && head.right == null){
            return;
        }
        Node temp = head.left;
        head.left = head.right;
        head.right = temp;

        if (head.left != null){
            MirrorRecursively(head.left);
        }
        if (head.right != null){
            MirrorRecursively(head.right);
        }
    }

    public static void Mirror(Node head){
        if (head == null){
            return;
        }
        Stack<Node> st = new Stack<>();
        Node temp = head;
        while (temp != null || !st.isEmpty()){
            while (temp!=null){
                st.push(temp);
                if (temp.left != null || temp.right != null){
                    Node change = temp.left;
                    temp.left = temp.right;
                    temp.right = change;
                }
                temp = temp.left;
            }
            if (!st.empty()){
                Node e = st.pop();
                temp = e.right;
            }
        }

    }

面试题28:对称的二叉树

在原树上进行先序遍历得到的序列,和镜像上先根后右再左得到的序列应相同,且需考虑空指针;
直接按照镜像的规则进行比较;
 public static boolean isSymmertrical(Node head){
        if (head == null){
            return false;
        }
        return compare(head,head);
    }
    public static boolean compare(Node head1, Node head2){
        if (head1 == null && head2 == null){
            return true;
        }
        if (head1 == null || head2 == null){
            return false;
        }

        if (head1.value != head2.value){
            return false;
        }

        return compare(head1.left,head2.right) && compare(head1.right,head2.left);
    }

面试题29:顺时针打印矩阵

将问题化简为循环打印圈的问题,圈的起点是有规律的(col=row);再在一圈中化简为4步,每步设定判断条件;
    public static void PrintMatrix(int[][] matrix,int rows,int cols){
        if (matrix == null || rows <=0 || cols <=0){
            return;
        }
        int start = 0;
        while (start*2<cols && start*2<rows){
            PrintCircle(start,cols,rows,matrix);
            start++;
        }
    }
    public static void PrintCircle(int start,int cols,int rows,int[][] matrix){
        for(int x = start;x<=cols - start -1;x++){
            System.out.print(matrix[start][x]);
        }
        if (rows-start-1-start<=0){
            return;
        }
        for (int x = start+1;x<= rows-start-1;x++){
            System.out.print(matrix[x][cols-start-1]);
        }
        if (cols-start-1-start<=0){
            return;
        }
        for (int x = cols-start-1-1;x>=start;x--){
            System.out.print(matrix[rows-start-1][x]);
        }
        if (rows-start-1-start<=1){
            return;
        }
        for (int x = rows-start-1-1;x>=start+1;x--){
            System.out.print(matrix[x][start]);
        }
    }

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

min,push,pop的时间都是o(1),使用链栈;在查找最小值时不能使用遍历 ,也就是说需要记录下最小值;但最小值有可能随着栈的弹出而进行改变,由于无法遍历,只能在push的时候,将每步的最小值都记录下来,用栈记录,和pop保持一致,维持栈顶是最小数;
class  stack_min{
    private Node head;
    private Node min_head;
    class Node{
        private int data;
        Node next;
        Node(int data){
            this.data = data;
        }
    }

    stack_min(){
        head = null;
        min_head = null;
    }

    public void push(int value){
        Node temp = new Node(value);
        temp.next = head;
        head = temp;

        if (min_head == null){
            Node min = new Node(value);
            min.next = min_head;
            min_head = min;
        }else {
            Node min = null;
            if (value<min_head.data){
                min = new Node(value);
            }else {
                min = new Node(min_head.data);
            }
            min.next = min_head;
            min_head = min;
        }
    }

    public int pop(){
        if (head == null){
            return -1;
        }
        int data = head.data;
        head = head.next;

        min_head = min_head.next;
        return data;
    }

    public int getmin(){
        return min_head.data;
    }
}

面试题31:栈的压入,弹出序列

设置辅助栈,按弹出序列模拟压入,若栈顶非当前元素,则在压入序列中开始扫描并压入,若有当前元素,到当前元素压入停止,若直到压入序列完依旧没找到当前元素,则失败;
 public static boolean matchstack(int[] stack_push,int[] stack_pop){
        if (stack_push == null || stack_pop == null ||stack_push.length == 0 || stack_pop.length ==0 || stack_pop.length > stack_push.length){
            return false;
        }
        int stack_push_index = 0;
        Stack<Integer> st = new Stack<>();
        stack_push_index = addnew(st,stack_push,stack_pop[0],stack_push_index);
        if (st.peek() != stack_pop[0]){
            return false;
        }
        st.pop();

        for (int x = 1;x<stack_pop.length;x++){
            int top = st.peek();
            if (top != stack_pop[x]){
                stack_push_index = addnew(st,stack_push,stack_pop[x],stack_push_index);
                if (st.peek() != stack_pop[x]){
                    return false;
                }else {
                    st.pop();
                }

            }else {
                st.pop();
            }
        }
        return true;
    }
    public static int addnew(Stack<Integer> st,int[] stack_push,int x,int stack_push_index){
        int temp = stack_push_index;
        while (temp < stack_push.length){
            st.push(stack_push[temp]);
            temp++;
            if (stack_push[temp-1] == x){
                break;
            }

        }

        return temp;
    }

面试题32_1:从上到下打印二叉树

按层次遍历,利用队列,节点出队时访问,且将其左右子树加入队列中;
 public static void Printtree(Node head){
        if (head == null){
            return;
        }
        ArrayDeque<Node> de = new ArrayDeque<>();
        de.add(head);

        while (!de.isEmpty()){
            Node temp = de.pollFirst();
            System.out.print(temp.getData());
            if (temp.left!=null){
                de.add(temp.left);
            }
            if (temp.right != null){
                de.add(temp.right);
            }
        }
    }

面试题32_2:分行从上到下打印二叉树

两个变量,一个记录本行还要打印的数目,一个记录下行需要打印的数据,本行打印完后,本行打印数目 = 下行需要打印的数目,下行打印的数目清零;
public static void Printtree(Node head){
        if (head == null){
            return;
        }
        ArrayDeque<Node> de = new ArrayDeque<>();
        de.add(head);
        int tobePrint = 1;
        int nextline = 0;

        while (tobePrint!=0){
            Node temp = de.pollFirst();
            System.out.print(temp.getData());
            tobePrint -- ;
            if (temp.left != null){
                de.add(temp.left);
                nextline ++;
            }
            if (temp.right != null){
                de.add(temp.right);
                nextline ++;
            }
            if (tobePrint == 0){
                System.out.print("\n");
                tobePrint = nextline;
                nextline = 0;
            }
        }
    }

面试题32_3:之字形打印二叉树

用两个栈进行存储,将当前行与下一行进行分隔存储,根据当前行是否为奇数来判断入栈的顺序
public static void Print(Node root){
        if (root == null){
            return;
        }
        Stack<Node> st1 = new Stack<>();
        Stack<Node> st2 = new Stack<>();
        st1.push(root);
        boolean isodd = false;
        while (!st1.empty()){
            Node temp = st1.pop();
            System.out.print(temp.data);
            if (isodd){
                if (temp.right!=null){
                    st2.push(temp.right);
                }
                if(temp.left != null){
                    st2.push(temp.left);
                }
            }else {

                if (temp.left!=null){
                    st2.push(temp.left);
                }
                if(temp.right != null){
                    st2.push(temp.right);
                }
            }

            if (st1.empty()){
                isodd = !isodd;
                Stack<Node> st = st2;
                st2 = st1;
                st1 = st;
                System.out.print("\n");
            }
        }
    }

面试题33_1:二叉搜索树的后序遍历序列

后序序列的最后一个元素是二叉树的根元素,由于是二叉搜索树,则根将序列可以分为两部分,一部分大于根,一部分小于根;

采用递归的办法进行判断;

public static boolean issearchtree(int[] nums){
        if (nums == null || nums.length == 0){
            return false;
        }
        int lenth = nums.length;
        if (lenth == 1){
            return true;
        }
        return issearch_core(nums,0,lenth-2,nums[lenth-1]);

    }
    public static boolean issearch_core(int[] nums,int start,int end,int data){
        if (start >= end){
            return true;
        }
        int index = start;
        for (;index<=end;index++){
            if (nums[index]>data){
                break;
            }
        }
        System.out.print(index);
        if (index == end+1){
            return issearch_core(nums,start,end-1,nums[end]);
        }else {
            for (int x = index; x <= end; x++) {
                if (nums[x] < data) {
                    return false;
                }
            }
            return issearch_core(nums,start,index-2,nums[index-1]) && issearch_core(nums,index,end-1,nums[end]);
        }
    }

面试题33_2:二叉搜索树的前序遍历序列

与后序序列的判断相似,只是根变为序列的第一个元素,只用改动角标
public static boolean issearchtree(int[] nums){
        if (nums == null || nums.length == 0){
            return false;
        }
        int lenth = nums.length;
        if (lenth == 1){
            return true;
        }
        return issearch_core(nums,1,lenth-1,nums[0]);

    }
    public static boolean issearch_core(int[] nums,int start,int end,int data){
        if (start >= end){
            return true;
        }
        int index = start;
        for (;index<=end;index++){
            if (nums[index]>data){
                break;
            }
        }
        System.out.print(index);
        if (index == end+1){
            return issearch_core(nums,start+1,end,nums[start]);
        }else {
            for (int x = index; x <= end; x++) {
                if (nums[x] < data) {
                    return false;
                }
            }
            return issearch_core(nums,start+1,index-1,nums[start]) && issearch_core(nums,index+1,end,nums[index]);
        }
    }

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

寻找所有路径的过程需要遍历所有的叶子节点,因为是二叉树,可以在前序遍历中完成。记录下来的路径,当遇到叶子节点时判断,若不是叶子节点则继续,在返回父节点时,从路径中删除,路径使用栈来表示;
 public static void FindPath(Node root,int expectedsum){
        if (root == null){
            return;
        }
        Stack<Node> st = new Stack<>();
        int currentsum = 0;
        FindPath_core(root,expectedsum,st,currentsum);
    }
    public static void FindPath_core(Node temp,int expectedsum,Stack<Node> st,int currentsum){
        currentsum += temp.data;
        st.push(temp);

        boolean isLeaf = (temp.left == null) && (temp.right == null);
        if (currentsum == expectedsum && isLeaf){
            ArrayList<Node> ar = new ArrayList<Node>();
            while (!st.empty()){
                ar.add(st.pop());
            }
            for(int x = ar.size()-1;x>=0;x--){
                System.out.print(ar.get(x).data);
                st.push(ar.get(x));
            }

            System.out.print("\n");
        }

        if (temp.left != null){
            FindPath_core(temp.left,expectedsum,st,currentsum);
        }
        if (temp.right != null){
            FindPath_core(temp.right,expectedsum,st,currentsum);
        }
        //返回父节点之前在路径上删除该节点
        st.pop();
    }

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

依次复制n个并将其连接,再遍历源链表,找到每个节点的随机指针指向的节点,从头开始需要多少步,则在新链表上走同样步数可得对应节点;o(n[2])
依次复制n个并将其连接,同时记录下,源节点到对应节点的对应关系。o(n), o(n)
复制,并插入在源节点后面;新的指针应指向对应的复制出的节点(源指向的后一个节点),再按奇数将链表断开成两个。o(n)
public static Node copyComplicated(Node head){
        if (head == null){
            return null;
        }
        if (head.next == null){
            return head;
        }
        copy(head);
        Link(head);
        return breakList(head);
    }
    public static void copy(Node head){
        Node temp = head;
        while (temp != null){
            Node newNode = new Node(temp.data);
            newNode.next = temp.next;
            temp.next = newNode;
            temp = newNode.next;
        }
    }

    public static void Link(Node head){
        Node temp = head;
        while (temp != null){
            if (temp.m_sSibling != null){
                temp.next.m_sSibling = temp.m_sSibling.next;
            }
            temp = temp.next.next;
        }
    }
    public static Node breakList(Node head){
        Node temp = head;
        Node newhead = new Node(-1);
        Node newhead_temp = newhead;
        while (temp != null){


                newhead_temp.next = temp.next;
                newhead_temp = newhead_temp.next;

                temp.next = temp.next.next;
                temp = temp.next;

        }
        return newhead.next;
    }

面试题36:二叉搜索树和双向链表

中序遍历,处理根节点时,将其与左子树的最右节点和右子树的最左节点相连。
    //用于共享的变量这个地方无法使用c++中的地址来做,暂时只想到申明了一个类变量来存储
    static Node last;
    public static void main(String[] args){
       Node t1 = new Node(10);
       Node t2 = new Node(6);
       Node t3 = new Node(14);
       Node t4 = new Node(4);
       Node t5 = new Node(8);
       Node t6 = new Node(12);
       Node t7 = new Node(16);

       t1.right= t3;
       t1.left = t2;
       t2.left = t4;
       t2.right = t5;
       t3.left = t6;
       t3.right = t7;

       Node head = turnTree(t1);
       print(head);

    }
    public static Node turnTree(Node root){
        if (root == null){
            return null;
        }
        if (root.left == null && root.right == null){
            return root;
        }
        ConvertNode(root);
        while (last.left!=null){
            last = last.left;
        }
        return last;

    }
    public static void ConvertNode(Node head){
        if (head == null){
            return;
        }
        if (head.left != null){
            ConvertNode(head.left);
        }
        head.left = last;
        if (last != null){
            last.right = head;
        }
        last = head;

        if (head.right != null){
            ConvertNode(head.right);
        }
    }

面试题37:序列化二叉树

采用前序+中序的方式表示树会无法还原有相同节点的树,所以只能采用加上特殊字符表示空的序列来进行表示,还原的过程与序列化的过程相对应。
public static Node turnArraytoTree(ArrayList<String> ar){
        if (ar == null || ar.size() == 0){
            return null;
        }
        String num = ar.remove(0);
        if (num == "$"){
            return null;
        }
        Node nex = new Node(Integer.parseInt(num));
        nex.left = turnArraytoTree(ar);
        nex.right = turnArraytoTree(ar);
        return nex;
    }

    public static ArrayList<String> turnTreetoArray(Node root){
        ArrayList<String> ar = new ArrayList<>();
        if (root ==null){
            return ar;
        }
        turnTreetoArray_core(root,ar);
        return ar;
    }
    public static void turnTreetoArray_core(Node temp,ArrayList<String> ar){
        if (temp == null){
            ar.add("$");
            return;
        }
        ar.add(temp.data+"");

        turnTreetoArray_core(temp.left,ar);
        turnTreetoArray_core(temp.right,ar);

    }

面试题38_1:字符串的排列

将字符串看为两个部分,首字符和剩余,第一层循环用于将首字符与剩余的进行交换,第二层则递归的将剩余的字符也看做两部分;
    public static void Permutation(char[] test){
        if (test == null || test.length == 0){
            return ;
        }

        Permutation_core(test,0);
    }
    public static void Permutation_core(char[] test,int first){
        if (first == test.length-1){
            for (char x:test){
                System.out.print(x);
            }
            System.out.println("\n");
        }
        else {
            for (int x = first;x<test.length;x++){
                char temp = test[x];
                test[x] = test[first];
                test[first] = temp;

                Permutation_core(test,first+1);

                temp = test[x];
                test[x] = test[first];
                test[first] = temp;
            }
        }
    }

面试题38_2:求输入字符的组合

求n个数长度为m的组合 =  剩下的n-1个数中选择m-1个  + 剩下的n-1个数中选择m个(当剩下的还有>=m个时)

输入的n个字符可以构成1,2...n的组合;

    public static void getZuhe(char[] chars){
        if (chars == null || chars.length == 0){
            return;
        }
        if (chars.length == 1){
            System.out.print(chars[0]);
            return;
        }
        String temp = "";
        for (int x = 1;x<= chars.length;x++){
            getZuhe_core(chars,0,x,temp);
        }
    }
    public static void getZuhe_core(char[] chars, int first, int num,String temp){
        if (num == 0){
            System.out.println(temp);
            return;
        }
        if (chars.length-1-first >= num-1) {
            getZuhe_core(chars, first + 1, num - 1, temp + chars[first]);
        }
        if (chars.length-1-first >= num){
            getZuhe_core(chars,first+1,num,temp);
        }
    }

面试题38_3:把8个数字放在正方形的8个顶点上

求8个数字的所有排列,判断排列是否满足3组求和条件,存在满足的情况则存在;
public static boolean getPailie(int[] nums){
        if ( nums == null || nums.length != 8){
            return false;
        }

        return getPailie_core(nums,0);
    }
    public static boolean getPailie_core(int[] nums , int first){
        if (first == nums.length -1){
            return judge(nums);

        }
        for (int x = first;x<=nums.length-1;x++){
            int temp = nums[x];
            nums[x] = nums[first];
            nums[first] = temp;

            boolean index = getPailie_core(nums,first+1);
            if (index == true){
                return true;
            }

            temp = nums[x];
            nums[x] = nums[first];
            nums[first] = temp;
        }
        return false;
    }
    public static boolean judge(int[] nums){
        if (nums[0]+nums[1]+nums[2]+nums[3] == nums[4]+nums[5]+nums[6]+nums[7] &&
                nums[0]+nums[2]+nums[4]+nums[6] == nums[1]+nums[3]+nums[5]+nums[7] &&
                nums[0] +nums[1]+nums[4]+nums[5] == nums[2] +nums[3]+nums[6]+nums[7]){
            return true;
        }else {
            return false;
        }
    }

面试题38_4:8皇后问题

8位皇后占8行,再用一个8位的数组分别表示每行的皇后在第几列,用0-7初始化保证列不相同,求出数组的排列,再判断在此排列下,是否会有两个皇后在同一对角线上。同一对角线的行之差 = 列之差;
//递归中可以选择3种方式传递参数,1.设全局变量 2.利用函数返回值更新 3.设局部变量,不断累加或更改;    
public static int getPailie(){
        int[] nums = {0,1,2,3,4,5,6,7};

        return getPailie_core(nums,0);
//        return count;
    }
    public static int getPailie_core(int[] nums , int first){
        int count = 0;
        if (first == nums.length -1){
            if (judge(nums) == true){
                count += 1;
            }
            return count;
        }
        for (int x = first;x<=nums.length-1;x++){
            int temp = nums[x];
            nums[x] = nums[first];
            nums[first] = temp;

            count += getPailie_core(nums,first+1);

            temp = nums[x];
            nums[x] = nums[first];
            nums[first] = temp;
        }
        return count;
    }
    public static boolean judge(int[] nums){
        for (int x = 0; x< nums.length -1;x++){
            for (int y = x+1;y <= nums.length -1 ;y++){
                if ( Math.abs(y-x) == Math.abs(nums[y]-nums[x])){
                    return false;
                }
            }
        }
        return true;
    }


猜你喜欢

转载自blog.csdn.net/u011010851/article/details/80098408
今日推荐