package com.freetymekiyan.algorithms.level.easy;

import org.junit.Assert;
import org.junit.Test;

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

/**
 * Given a string containing just the characters '(', ')', '{', '}', '[' and ']', determine if the input string is
 * valid.
 * <p>
 * The brackets must close in the correct order, "()" and "()[]{}" are all valid but "(]" and "([)]" are not.
 * <p>
 * Company Tags: Google, Airbnb, Facebook, Twitter, Zenefits, Amazon, Microsoft, Bloomberg
 * Tags: Stack, String
 * Similar Problems: (M) Generate Parentheses, (H) Longest Valid Parentheses, (H) Remove Invalid Parentheses
 */
public class ValidParentheses {

    /**
     * Stack.
     * Use stack to check pair.
     * Whenever there is a valid pair, pop from stack since it is already valid.
     * Quick check: If string length not even, return false.
     * Create a stack.
     * For each character c in the string given:
     * | If c is a left paren, push to stack.
     * | Else if stack is not empty, and c matches with the peek:
     * |   Pop the left paren from stack.
     * | Else return false.
     * After the check, the stack should be empty because all pairs are popped.
     * Otherwise return false.
     */
    public boolean isValid(String s) {
        if (s == null || s.length() == 0) {
            return false;
        }
        if (s.length() % 2 != 0) { // String length must be even.
            return false;
        }
        Deque<Character> stk = new ArrayDeque<>();
        for (Character c : s.toCharArray()) {
            if ("({[".indexOf(c) != -1) { // Push left parens.
                stk.push(c);
            } else if (!stk.isEmpty() && isMatch(stk.peek(), c)) {
                stk.pop();
            } else {
                return false;
            }
        }
        return stk.isEmpty();
    }

    private boolean isMatch(char c1, char c2) {
        return (c1 == '(' && c2 == ')') || (c1 == '{' && c2 == '}') || (c1 == '[' && c2 == ']');
    }

    /**
     * Stack.
     * Push right parens onto stack instead of left ones.
     * This way match function can be saved.
     * When it is a right paren:
     * | If the stack is empty, return false since there is no matching left.
     * | If paren popped from stack is different from c, doesn't match, return false.
     * Finally, return true if the stack is empty. Otherwise false.
     */
    public boolean isValidB(String s) {
        Stack<Character> stack = new Stack<>();
        String left = "({[";
        String right = ")}]";
        for (char c : s.toCharArray()) {
            int index = left.indexOf(c);
            if (index != -1) { // Is left paren.
                stack.push(right.charAt(index)); // Push right.
            } else if (stack.isEmpty() || stack.pop() != c) {
                return false;
            }
        }
        return stack.isEmpty();
    }

    @Test
    public void testExamples() {
        Assert.assertTrue(isValid("()"));
        Assert.assertTrue(isValid("()[]{}"));
        Assert.assertFalse(isValid("([)]"));
        Assert.assertTrue(isValid("[({(())}[()])]"));
        Assert.assertFalse(isValid("a[a(a{a(a(.)a)a}x[a(a)v]w)q]z"));
    }
}

@@ -148,32 +148,8 @@
 que;
-%0Aimport java.util.Stack;
 %0A%0A/*
@@ -2442,21 +2442,21 @@
         
-Stack
+Deque
 %3CCharact
@@ -2471,21 +2471,26 @@
 k = new 
-Stack
+ArrayDeque
 %3C%3E();%0A  

update valid parentheses