1. Introduction to Stack in Java

  • Definition: A stack is a linear data structure that follows the Last In First Out (LIFO) principle.
  • Operations:
    • Push: Adds an element to the top of the stack.
    • Pop: Removes and returns the top element of the stack.
    • Peek: Returns the top element without removing it.
    • isEmpty: Checks if the stack is empty.
    • size: Returns the number of elements in the stack.

2. Implementing a Stack in Java

  • Using java.util.Stack:

    import java.util.Stack;
    
    public class StackExample {
        public static void main(String[] args) {
            Stack<Integer> stack = new Stack<>();
            stack.push(10);
            stack.push(20);
            stack.push(30);
    
            System.out.println("Top element is: " + stack.peek());
            System.out.println("Stack size: " + stack.size());
    
            while (!stack.isEmpty()) {
                System.out.println("Popped element: " + stack.pop());
            }
        }
    }
    
  • Custom Stack Implementation:

    class MyStack {
        private int maxSize;
        private int[] stackArray;
        private int top;
    
        public MyStack(int size) {
            maxSize = size;
            stackArray = new int[maxSize];
            top = -1;
        }
    
        public void push(int value) {
            if (top < maxSize - 1) {
                stackArray[++top] = value;
            } else {
                System.out.println("Stack is full!");
            }
        }
    
        public int pop() {
            return (top >= 0) ? stackArray[top--] : -1;
        }
    
        public int peek() {
            return (top >= 0) ? stackArray[top] : -1;
        }
    
        public boolean isEmpty() {
            return (top == -1);
        }
    
        public int size() {
            return top + 1;
        }
    }
    

3. Common Interview Questions

  • Reverse a String Using Stack:

    public class ReverseString {
        public static void main(String[] args) {
            String input = "Hello";
            Stack<Character> stack = new Stack<>();
    
            for (char ch : input.toCharArray()) {
                stack.push(ch);
            }
    
            StringBuilder reversed = new StringBuilder();
            while (!stack.isEmpty()) {
                reversed.append(stack.pop());
            }
    
            System.out.println("Reversed String: " + reversed.toString());
        }
    }
    
  • Check for Balanced Parentheses:

    public class BalancedParentheses {
        public static boolean isBalanced(String expression) {
            Stack<Character> stack = new Stack<>();
            for (char ch : expression.toCharArray()) {
                if (ch == '(' || ch == '{' || ch == '[') {
                    stack.push(ch);
                } else if (ch == ')' || ch == '}' || ch == ']') {
                    if (stack.isEmpty()) return false;
                    char last = stack.pop();
                    if ((ch == ')' && last != '(') || (ch == '}' && last != '{') || (ch == ']' && last != '[')) {
                        return false;
                    }
                }
            }
            return stack.isEmpty();
        }
    
        public static void main(String[] args) {
            String expression = "{[()]}";
            System.out.println("Is balanced: " + isBalanced(expression));
        }
    }
    
  • Evaluate a Postfix Expression:

    public class PostfixEvaluation {
        public static int evaluatePostfix(String expression) {
            Stack<Integer> stack = new Stack<>();
            for (char ch : expression.toCharArray()) {
                if (Character.isDigit(ch)) {
                    stack.push(ch - '0');
                } else {
                    int b = stack.pop();
                    int a = stack.pop();
                    switch (ch) {
                        case '+':
                            stack.push(a + b);
                            break;
                        case '-':
                            stack.push(a - b);
                            break;
                        case '*':
                            stack.push(a * b);
                            break;
                        case '/':
                            stack.push(a / b);
                            break;
                    }
                }
            }
            return stack.pop();
        }
    
        public static void main(String[] args) {
            String expression = "231*+9-";
            System.out.println("Postfix evaluation: " + evaluatePostfix(expression));
        }
    }
    

4. Advanced Topics

  • Implementing a Min Stack:

    class MinStack {
        private Stack<Integer> stack = new Stack<>();
        private Stack<Integer> minStack = new Stack<>();
    
        public void push(int x) {
            stack.push(x);
            if (minStack.isEmpty() || x <= minStack.peek()) {
                minStack.push(x);
            }
        }
    
        public void pop() {
            if (stack.pop().equals(minStack.peek())) {
                minStack.pop();
            }
        }
    
        public int top() {
            return stack.peek();
        }
    
        public int getMin() {
            return minStack.peek();
        }
    }
    
  • Stack Using Queues:

    import java.util.LinkedList;
    import java.util.Queue;
    
    class StackUsingQueues {
        private Queue<Integer> queue1 = new LinkedList<>();
        private Queue<Integer> queue2 = new LinkedList<>();
    
        public void push(int x) {
            queue1.add(x);
        }
    
        public int pop() {
            while (queue1.size() > 1) {
                queue2.add(queue1.remove());
            }
            int poppedElement = queue1.remove();
            Queue<Integer> temp = queue1;
            queue1 = queue2;
            queue2 = temp;
            return poppedElement;
        }
    
        public int top() {
            while (queue1.size() > 1) {
                queue2.add(queue1.remove());
            }
            int topElement = queue1.peek();
            queue2.add(queue1.remove());
            Queue<Integer> temp = queue1;
            queue1 = queue2;
            queue2 = temp;
            return topElement;
        }
    
        public boolean isEmpty() {
            return queue1.isEmpty();
        }
    }
    

5. Tips for Interviews

  • Understand the Basics: Make sure you understand basic stack operations and their time complexities.
  • Practice Common Problems: Focus on problems like balanced parentheses, postfix evaluation, and reverse strings.
  • Advanced Problems: Be comfortable with implementing stacks using arrays or linked lists, and solving problems like Min Stack or Stack using Queues.
  • Explain Your Thought Process: During the interview, clearly explain your approach and thought process.
  • Optimize Your Solutions: Think about edge cases and how to optimize your stack implementations.