牛客網初級算法之四

題目1:前序,中序,後序 非遞歸遍歷二叉樹node

代碼:this

前序:spa

public static void preOrderUnRecur(Node head) {
        System.out.print("pre-order: ");
        if (head != null) {
            Stack<Node> stack = new Stack<Node>();
            stack.add(head);
            while (!stack.isEmpty()) {
                head = stack.pop();
                System.out.print(head.value + " ");
                if (head.right != null) {
                    stack.push(head.right);
                }
                if (head.left != null) {
                    stack.push(head.left);
                }
            }
        }
        System.out.println();
    }

中序:指針

public static void inOrderUnRecur(Node head) {
        System.out.print("in-order: ");
        if (head != null) {
            Stack<Node> stack = new Stack<Node>();
            while (!stack.isEmpty() || head != null) {
                if (head != null) {
                    stack.push(head);
                    head = head.left;
                } else {
                    head = stack.pop();
                    System.out.print(head.value + " ");
                    head = head.right;
                }
            }
        }
        System.out.println();
    }

後序code

最簡單的思路:blog

前序的順序爲 中左右 後序的順序爲 左右中,若是前序遍歷變爲 中右左,那麼後序遍歷和前序遍歷的順序就會正好相反,如何讓前序遍歷 變爲 中右左呢,就是把left和right入站的順序遞歸

改變一下就行,而後在每次打印節點的地方,換成把節點加入到另外一個棧,以後遍歷這個站就是 後序遍歷的節點順序隊列

public static void posOrderUnRecur1(Node head) {
        System.out.print("pos-order: ");
        if (head != null) {
            Stack<Node> s1 = new Stack<Node>();
            Stack<Node> s2 = new Stack<Node>();
            s1.push(head);
            while (!s1.isEmpty()) {
                head = s1.pop();
                s2.push(head);
                if (head.left != null) {
                    s1.push(head.left);
                }
                if (head.right != null) {
                    s1.push(head.right);
                }
            }
            while (!s2.isEmpty()) {
                System.out.print(s2.pop().value + " ");
            }
        }
        System.out.println();
    }

題目二:get

二叉樹的序列號和反序列化it

思路一:利用遞歸方法:

序列化:

public static String serialByPre(Node head) {
        if (head == null) {
            return "#!";
        }
        String res = head.value + "!";
        res += serialByPre(head.left);
        res += serialByPre(head.right);
        return res;
    }

反序列化:

怎麼序列化的就怎麼反序列化:

public static Node reconByPreString(String preStr) {
        String[] values = preStr.split("!");
        Queue<String> queue = new LinkedList<String>();
        for (int i = 0; i != values.length; i++) {
            queue.offer(values[i]);
        }
        return reconPreOrder(queue);
    }

    public static Node reconPreOrder(Queue<String> queue) {
        String value = queue.poll();
        if (value.equals("#")) {
            return null;
        }
        Node head = new Node(Integer.valueOf(value));
        head.left = reconPreOrder(queue);
        head.right = reconPreOrder(queue);
        return head;
    }

思路二:利用樹的層次

public static String serialByLevel(Node head) {
        if (head == null) {
            return "#!";
        }
        String res = head.value + "!";
        Queue<Node> queue = new LinkedList<Node>();
        queue.offer(head);
        while (!queue.isEmpty()) {
            head = queue.poll();
            if (head.left != null) {
                res += head.left.value + "!";
                queue.offer(head.left);
            } else {
                res += "#!";
            }
            if (head.right != null) {
                res += head.right.value + "!";
                queue.offer(head.right);
            } else {
                res += "#!";
            }
        }
        return res;
    }

    public static Node reconByLevelString(String levelStr) {
        String[] values = levelStr.split("!");
        int index = 0;
        Node head = generateNodeByString(values[index++]);
        Queue<Node> queue = new LinkedList<Node>();
        if (head != null) {
            queue.offer(head);
        }
        Node node = null;
        while (!queue.isEmpty()) {
            node = queue.poll();
            node.left = generateNodeByString(values[index++]);
            node.right = generateNodeByString(values[index++]);
            if (node.left != null) {
                queue.offer(node.left);
            }
            if (node.right != null) {
                queue.offer(node.right);
            }
        }
        return head;
    }

    public static Node generateNodeByString(String val) {
        if (val.equals("#")) {
            return null;
        }
        return new Node(Integer.valueOf(val));
    }

題目三:求二叉樹的後繼節點(每一個節點有parent指針,指向父親節點)

後繼節點是指二叉樹中序遍歷中,某個節點的後面的那個節點

思路:

經過概括總結,可分爲兩種狀況

狀況1:節點A的右子樹不爲空,那麼節點A的後繼爲 右子樹的 最左邊的孩子

狀況2:節點A的右子樹爲空,那麼開始從節點A不斷經過parent指針找到他的父節點,直到找到的 當前節點A' 的父親節點B的左孩子等於A',B就是節點A的後繼

特殊狀況爲 中序遍歷的最後一個節點,它沒有後繼,返回null

代碼以下:

public class SuccessorNode {

    public static class Node {
        public int value;
        public Node left;
        public Node right;
        public Node parent;

        public Node(int data) {
            this.value = data;
        }
    }

    public static Node getSuccessorNode(Node node) {
        if (node == null) {
            return node;
        }
        if (node.right != null) {
            return getLeftMost(node.right);
        } else {
            Node parent = node.parent;
            while (parent != null && parent.left != node) {
                node = parent;
                parent = node.parent;
            }
            return parent;
        }
    }

    public static Node getLeftMost(Node node) {
        if (node == null) {
            return node;
        }
        while (node.left != null) {
            node = node.left;
        }
        return node;
    }

    public static void main(String[] args) {
        Node head = new Node(6);
        head.parent = null;
        head.left = new Node(3);
        head.left.parent = head;
        head.left.left = new Node(1);
        head.left.left.parent = head.left;
        head.left.left.right = new Node(2);
        head.left.left.right.parent = head.left.left;
        head.left.right = new Node(4);
        head.left.right.parent = head.left;
        head.left.right.right = new Node(5);
        head.left.right.right.parent = head.left.right;
        head.right = new Node(9);
        head.right.parent = head;
        head.right.left = new Node(8);
        head.right.left.parent = head.right;
        head.right.left.left = new Node(7);
        head.right.left.left.parent = head.right.left;
        head.right.right = new Node(10);
        head.right.right.parent = head.right;

        Node test = head.left.left;
        System.out.println(test.value + " next: " + getSuccessorNode(test).value);
        test = head.left.left.right;
        System.out.println(test.value + " next: " + getSuccessorNode(test).value);
        test = head.left;
        System.out.println(test.value + " next: " + getSuccessorNode(test).value);
        test = head.left.right;
        System.out.println(test.value + " next: " + getSuccessorNode(test).value);
        test = head.left.right.right;
        System.out.println(test.value + " next: " + getSuccessorNode(test).value);
        test = head;
        System.out.println(test.value + " next: " + getSuccessorNode(test).value);
        test = head.right.left.left;
        System.out.println(test.value + " next: " + getSuccessorNode(test).value);
        test = head.right.left;
        System.out.println(test.value + " next: " + getSuccessorNode(test).value);
        test = head.right;
        System.out.println(test.value + " next: " + getSuccessorNode(test).value);
        test = head.right.right; // 10's next is null
        System.out.println(test.value + " next: " + getSuccessorNode(test));
    }

}

題目四:判斷一個樹是否是平衡二叉樹?

平衡二叉樹是指任何樹的左子樹和右子樹的高度相差不大於1

思路

根據概念能夠分析出能夠用遞歸方法:

1 求出節點A的 左子樹高度

2 求出節點A的 右子樹高度

3 判斷高度差是否大於1,更新布爾值

public class IsBalancedTree {

    public static class Node {
        public int value;
        public Node left;
        public Node right;

        public Node(int data) {
            this.value = data;
        }
    }

    public static boolean isBalance(Node head) {
        boolean[] res = new boolean[1];
        res[0] = true;
        getHeight(head, 1, res);
        return res[0];
    }

    public static int getHeight(Node head, int level, boolean[] res) {
        if (head == null) {
            return level;
        }
        int lH = getHeight(head.left, level + 1, res);
        if (!res[0]) {
            return level;
        }
        int rH = getHeight(head.right, level + 1, res);
        if (!res[0]) {
            return level;
        }
        if (Math.abs(lH - rH) > 1) {
            res[0] = false;
        }
        return Math.max(lH, rH);
    }

    public static void main(String[] args) {
        Node head = new Node(1);
        head.left = new Node(2);
        head.right = new Node(3);
        head.left.left = new Node(4);
        head.left.right = new Node(5);
        head.right.left = new Node(6);
        head.right.right = new Node(7);

        System.out.println(isBalance(head));

    }

}

這裏經過層級字段求出 高度,和單純求每層節點的高度是一個道理。

 

題目五:判斷一個樹是否是二叉搜索樹?

比較好理解的思路:中序遍歷 以後的升序序列就是 二叉搜索樹

bool isValidBST(TreeNode* root) {
    stack<TreeNode*>que;
    TreeNode * p = root;
    int pre=INT_MIN;
    int num=0;
    while (p|| que.empty()==false) {
        if(p){
            que.push(p);
            p=p->left;
        }
        else{
            TreeNode * node = que.top();
            que.pop();
            int val = node->val;
            printf("%d\n",val);
            if(num==1){
                if(val<=pre){
                    return false;
                }
            }
           
            num=1;
            pre=val;
            p=node->right;
        }
    }
    return true;
}

題目六:判斷一個樹是否爲徹底二叉樹?

思路:

能夠藉助隊列

在兩種狀況下,必定不是徹底二叉樹

狀況1: 左子樹爲空,右子樹不爲空

狀況2:開始葉子節點遍歷的時候,若是不是葉子節點,就不是徹底二叉樹

public static boolean isCBT(Node head) {
        if (head == null) {
            return true;
        }
        Queue<Node> queue = new LinkedList<Node>();
        boolean leaf = false;
        Node l = null;
        Node r = null;
        queue.offer(head);
        while (!queue.isEmpty()) {
            head = queue.poll();
            l = head.left;
            r = head.right;
            if ((leaf && (l != null || r != null)) || (l == null && r != null)) {
                return false;
            }
            
            if (l != null) {
                queue.offer(l);
            }
            if (r != null) {
                queue.offer(r);
            } else {
                leaf = true;
            }
        }
        return true;
    }

題目七:已知一棵徹底二叉樹,求其節點的個數 要求:時間複雜度低於O(N),N爲這棵樹的節點個數

思路1:若是時間複雜度爲O(N),那麼就能夠遍歷這棵樹,可是沒有利用徹底二叉樹的特色。

這裏咱們每次看當前節點的右子樹的是否達到了最底部。

1 若是達到了,那麼當前點的左子樹必定就是徹底二叉樹,能夠利用h^2-1求出左子樹的節點數目,

而後遞歸求解右子樹的節點個數。

2 若是沒達到,那麼當前節點的右子樹必定是徹底二叉樹,節點數爲(h-1)^2-1 ,而後遞歸求解左子樹的節點個數

3 遞歸終止條件爲 到達葉節點,返回1

代碼:

public class CompleteTreeNodeNumber {

    public static class Node {
        public int value;
        public Node left;
        public Node right;

        public Node(int data) {
            this.value = data;
        }
    }

    public static int nodeNum(Node head) {
        if (head == null) {
            return 0;
        }
        return bs(head, 1, mostLeftLevel(head, 1));
    }

    public static int bs(Node node, int l, int h) {
        if (l == h) {
            return 1;
        }
        if (mostLeftLevel(node.right, l + 1) == h) {
            return (1 << (h - l)) + bs(node.right, l + 1, h);
        } else {
            return (1 << (h - l - 1)) + bs(node.left, l + 1, h);
        }
    }

    public static int mostLeftLevel(Node node, int level) {
        while (node != null) {
            level++;
            node = node.left;
        }
        return level - 1;
    }

    public static void main(String[] args) {
        Node head = new Node(1);
        head.left = new Node(2);
        head.right = new Node(3);
        head.left.left = new Node(4);
        head.left.right = new Node(5);
        head.right.left = new Node(6);
        System.out.println(nodeNum(head));

    }

}

 思路2:

一顆樹爲徹底二叉樹就分爲兩種狀況:

一種是左子樹和右子樹的最大高度同樣,另外一種是左子樹比右子樹高度大1,因此能夠根據這兩種狀況寫遞歸:

第一種狀況 左子樹必定是徹底二叉樹,第二種狀況右子樹必定是徹底二叉樹:

int getDepth(TreeNode *node){
    int height = 0;
    while (node) {
        node = node->left;
        height++;
    }
    return height;
}

int getReturn(TreeNode * node){
    
    if(node==nullptr){
        return 0;
    }
    
    int h1= getDepth(node->left);
    int h2= getDepth(node->right);
    
    //若是 左右子樹 最大高度相等,左邊爲徹底二叉樹
    if(h1==h2){
       return (1<<h1)+ getReturn(node->right);
    }
    //右邊爲徹底二叉樹
    else {
        return (1<<h2)+ getReturn(node->left);
    }
    
}

//徹底二叉樹節點個數
int countNodes(TreeNode* root) {
    return getReturn(root);
}
相關文章
相關標籤/搜索