package com.freetymekiyan.algorithms.level.medium;

import java.util.ArrayDeque;
import java.util.Deque;

/**
 * One way to serialize a binary tree is to use pre-order traversal. When we encounter a non-null node, we record the
 * node's value. If it is a null node, we record using a sentinel value such as #.
 * <p>
 * _9_
 * /   \
 * 3     2
 * / \   / \
 * 4   1  #  6
 * / \ / \   / \
 * # # # #   # #
 * For example, the above binary tree can be serialized to the string "9,3,4,#,#,1,#,#,2,#,6,#,#", where # represents a
 * null node.
 * <p>
 * Given a string of comma separated values, verify whether it is a correct preorder traversal serialization of a binary
 * tree. Find an algorithm without reconstructing the tree.
 * <p>
 * Each comma separated value in the string must be either an integer or a character '#' representing null pointer.
 * <p>
 * You may assume that the input format is always valid, for example it could never contain two consecutive commas such
 * as "1,,3".
 * <p>
 * Example 1:
 * "9,3,4,#,#,1,#,#,2,#,6,#,#"
 * Return true
 * <p>
 * Example 2:
 * "1,#"
 * Return false
 * <p>
 * Example 3:
 * "9,#,#,1"
 * Return false
 * <p>
 * Tags: Stack
 */
public class VerifyPreorderSerializationOfABinaryTree {

    /**
     * Stack.
     * Iterate through the string characters.
     * If it's a number, just push to stack.
     * If it's a '#', we need to figure out some sub situations:
     * 1) If the top of the stack is a number, then this '#' is the left child, just push it.
     * 2) If the top of the stack is a '#', then this '#' is the right child, we should pop the subtree.
     * 2.1) After the subtree is popped, if the stack top is still '#', it means the subtree should be popped again.
     * 2.2) If the stack top is a number, we need to add a '#' to mark that the next node knows it's a right child.
     * https://discuss.leetcode.com/topic/35973/java-intuitive-22ms-solution-with-stack
     */
    public boolean isValidSerialization(String preorder) {
        Deque<String> stack = new ArrayDeque<>();
        String[] nodes = preorder.split(",");
        for (int i = 0; i < nodes.length; i++) {
            String curr = nodes[i];
            while ("#".equals(curr) && !stack.isEmpty() && "#".equals(stack.peek())) {
                stack.pop();
                if (stack.isEmpty()) {
                    return false;
                }
                stack.pop();
            }
            stack.push(curr);
        }
        return stack.size() == 1 && "#".equals(stack.peek());
    }

    /**
     * Degree.
     * A value provide 2 out degrees and 1 in degree, except root.
     * A '#' provide no out degree and 1 in degree.
     * https://discuss.leetcode.com/topic/35976/7-lines-easy-java-solution
     */
    public boolean isValidSerializationB(String preorder) {
        String[] nodes = preorder.split(",");
        int diff = 1;
        for (String node : nodes) {
            diff--;
            if (diff < 0) {
                return false;
            }
            if (!"#".equals(node)) {
                diff += 2;
            }
        }
        return diff == 0;
    }

}

add Verify Preorder Serialization of a Binary Tree