Stack相关算法

118 阅读3分钟

Stack

最大蓄水问题

11. Container With Most Water

Approach 1 : Brute Force

class Solution {
    public int maxArea(int[] height) {
        int len = height.length;
        int maximumArea = 0;
        for (int i = 0; i < len; i++) {
            for (int j = i + 1; j < len; j++) {
                maximumArea = Math.max(maximumArea, (j - i) * Math.min(height[i], height[j]));
            }
        }
        
        return maximumArea;
    }
}

Approach 2 : Two Pointer

class Solution {
    public int maxArea(int[] height) {
        int len = height.length;
        int maximumArea = 0, l = 0, r = len - 1;
        while(l < r){
            maximumArea = Math.max(maximumArea, Math.min(height[l], height[r]) * (r - l));
            if(height[l] < height[r])
                l++;
            else
                r--;
        }

        return maximumArea;
    }

    public static void main(String[] args) {
        Solution s = new Solution();
        int res = s.maxArea(new int[]{1, 8, 6, 2, 5, 4, 8, 3, 7});
        System.out.println(res);
    }
}
238. Product of Array Except Self

Approach 1 : Left and Right product lists

class Solution {
    public int[] productExceptSelf(int[] nums) {
        int len = nums.length;
        int[] leftProduct = new int[len];
        int[] rightProduct = new int[len];
        Arrays.fill(leftProduct, 1);
        Arrays.fill(rightProduct, 1);
        for (int i = 0; i + 1 < len; i++) {
            leftProduct[i + 1] = leftProduct[i] * nums[i]; 
        }
        for (int j = len - 1; j > 0; j--) {
            rightProduct[j - 1] = rightProduct[j] * nums[j];
        }
        
        int[] res = new int[len];
        for (int i = 0; i < len; i++) {
            res[i] = leftProduct[i] * rightProduct[i];
        }
        
        return res;
    }
}

Approach 2 : O(1) space approach

class Solution {
    public int[] productExceptSelf(int[] nums) {
        int len = nums.length;
        int[] res = new int[len];
        Arrays.fill(res, 1);
        for (int i = 0; i + 1 < len; i++) {
            res[i + 1] = res[i] * nums[i];
        }

        int product = nums[len - 1];
        for (int j = len - 2; j >= 0; j--) {
            res[j] = res[j] * product;
            product = product * nums[j];
        }
        
        return res;
    }
}
42. Trapping Rain Water

Approach 1 : Brute force

class Solution {
    public int trap(int[] height) {
        int ans = 0, n = height.length;
        int left_max, right_max;
        for (int i = 0; i < n; i++) {
            left_max = 0;
            right_max = 0;
            for (int j = 0; j < i; j++) {
                left_max = Math.max(left_max, height[j]);
            }
            for (int j = i + 1; j < n; j++) {
                right_max = Math.max(right_max, height[j]);
            }

            int min = Math.min(left_max, right_max);
            if(min != 0 && min > height[i]){
                ans += min - height[i];
            }
        }
        
        return ans;
    }
}

Approach 2 : Dynamic Programming

class Solution {
    public int trap(int[] height) {
        int n = height.length;
                if(n == 0)
            return 0;
        int[] left = new int[n], right = new int[n];
        left[0] = Integer.MIN_VALUE;
        for (int i = 1; i < n; i++) {
            left[i] = Math.max(left[i - 1], height[i - 1]);
        }
        right[n - 1] = Integer.MIN_VALUE;
        for (int j = n - 2; j >= 0; j--) {
            right[j] = Math.max(right[j + 1], height[j + 1]); 
        }
        
        int res = 0;
        for (int i = 0; i < n; i++) {
            int h = Math.min(left[i], right[i]);
            if(h != Integer.MIN_VALUE && h > height[i]){
                res += h - height[i];
            }
        }

        return res;
    }
}

Approach 3 : Using Stack

class Solution {
    public int trap(int[] height) {
        int ans = 0, current = 0;
        Stack<Integer> st = new Stack();
        while(current < height.length){
            while(!st.empty() && height[current] > height[st.peek()]){
                int top = st.pop();
                if(st.empty())
                    break;
                int distance = current - st.peek() - 1;
                int bounded_height = Math.min(height[current], height[st.peek()]) - height[top];
                ans += distance * bounded_height;
            }
            st.push(current++);
        }

        return ans;
    }
}

Approach 4 : Two Pointers

class Solution {
    public int trap(int[] height) {
        int left = 0, right = height.length - 1;
        int ans = 0;
        int leftMax = 0, rightMax = 0;
        while(left < right){
            if(height[left] < height[right]){
                if (height[left] >= leftMax) {
                    leftMax = height[left];
                } else {
                    ans += (leftMax - height[left]);
                }
                ++left;
            }else{
                if(height[right] >= rightMax){
                    rightMax = height[right];
                }else{
                    ans += (rightMax - height[right]);
                }
                right--;
            }
        }

        return ans;
    }
}

最大矩形面积

221. Maximal Square
class Solution {
    public int maximalSquare(char[][] matrix) {
        int res = 0;
        int m = matrix.length, n = matrix[0].length;
        int[][] dp = new int[m][n];
        for (int i = 0; i < m; i++) {
            dp[i][0] = matrix[i][0] == '1' ? 1 : 0;
            if(res == 0 && dp[i][0] == 1)
                res = 1;
        }
        for (int j = 0; j < n; j++) {
            dp[0][j] = matrix[0][j] == '1' ? 1 : 0;
            if(res == 0 && dp[0][j] == 1)
                res = 1;
        }

        for (int i = 1; i < m; i++) {
            for (int j = 1; j < n; j++) {
                if(matrix[i][j] != '0'){
                    dp[i][j] = Math.min(Math.min(dp[i - 1][j], dp[i][j - 1]), dp[i - 1][j - 1]) + 1;
                    res = Math.max(res, dp[i][j]);
                }
            }
        }

        return res * res;
    }
}
85. Maximal Rectangle
class Solution {
    public int maximalRectangle(char[][] matrix) {
        if(matrix == null || matrix.length == 0){
            return 0;
        }
        int rLen = matrix.length, cLen = matrix[0].length;
        int[] h = new int[cLen + 1];
        int max = 0;
        for (int row = 0; row < rLen; row++) {
            Stack<Integer> s = new Stack<>();
            s.push(-1);
            for (int i = 0; i <= cLen; i++) {
                if(i < cLen && matrix[row][i] == '1'){
                    h[i] += 1;
                }else
                    h[i] = 0;

                while(s.peek() != -1 && h[i] < h[s.peek()]){
                    max = Math.max(max, h[s.pop()] * (i - s.peek() - 1));
                }

                s.push(i);
            }
        }

        return max;
     }
}
84. Largest Rectangle in Histogram

算法思想,在栈中保持升序高度的索引,遇到比当前高度矮的进行处理

class Solution {
    public int largestRectangleArea(int[] heights) {
        int n = heights.length;
        Stack<Integer> s = new Stack<>();
        int maxArea = 0;
        for (int i = 0; i <= n; i++) {
            int h = (i == n ? 0 : heights[i]);
            if(s.isEmpty() || h >= heights[s.peek()]){
                s.push(i);
            }else{
                int tp = s.pop();
                maxArea = Math.max(maxArea, heights[tp] * (s.isEmpty() ? i : i - 1 - s.peek()));
                i--;
            }
        }
        
        return maxArea;
    }
}

二叉树遍历

94. Binary Tree Inorder Traversal
class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        Stack<TreeNode> st = new Stack<>();
        if(root != null)
            st.push(root);
        List<Integer> res = new ArrayList<>();
        while(!st.isEmpty()){
            TreeNode node = st.pop();
            if(node.left == null && node.right == null){
                res.add(node.val);
            }else{
                if(node.right != null){
                    st.push(node.right);
                    node.right = null;
                }
                st.push(node);
                if(node.left != null){
                    st.push(node.left);
                    node.left = null;
                }
            }
        }

        return res;
    }
}
144. Binary Tree Preorder Traversal
class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        Stack<TreeNode> st = new Stack<>();
        if(root != null)
            st.push(root);
        while(!st.isEmpty()){
            TreeNode node = st.pop();
            res.add(node.val);
            if(node.right != null){
                st.push(node.right);
            }
            if(node.left != null){
                st.push(node.left);
            }
        }
        
        return res;
    }
}
145. Binary Tree Postorder Traversal
class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        Stack<TreeNode> st = new Stack<>();
        if(root != null)
            st.push(root);
        while(!st.isEmpty()){
            TreeNode node = st.pop();
            if(node.left == null && node.right == null){
                res.add(node.val);
            }else{
                st.push(node);
                if(node.right != null){
                    st.push(node.right);
                    node.right = null;
                }
                if(node.left != null){
                    st.push(node.left);
                    node.left = null;
                }
            }
        }

        return res;
    }
}
103. Binary Tree Zigzag Level Order Traversal
class Solution {
    public List<List<Integer>> zigzagLevelOrder(TreeNode root) {
        List<List<Integer>> res = new ArrayList<>();
        Stack<TreeNode> st = new Stack<>();
        if(root == null)
            return res;
        boolean leftToRight = true;
        st.push(root);
        while(!st.isEmpty()){
            Stack<TreeNode> next = new Stack<>();
            List<Integer> tmp = new ArrayList<>();
            while(!st.isEmpty()){
                TreeNode node = st.pop();
                tmp.add(node.val);
                if(leftToRight) {
                    if (node.left != null) {
                        next.push(node.left);
                    }
                    if (node.right != null) {
                        next.push(node.right);
                    }
                }else{
                    if (node.right != null) {
                        next.push(node.right);
                    }
                    if (node.left != null) {
                        next.push(node.left);
                    }
                }
            }
            st = next;
            res.add(tmp);
            leftToRight = !leftToRight;
        }

        return res;
    }
}

表达式计算

227. Basic Calculator II

Approach 1 :Using Stack

class Solution {
    public int calculate(String s) {
        if(s == null || s.isEmpty())
            return 0;
        int length = s.length();
        Stack<Integer> stack = new Stack<>();
        int currentNumber = 0;
        char operation = '+';
        for (int i = 0; i < length; i++) {
            char currentChar = s.charAt(i);
            if (Character.isDigit(currentChar)) {
                currentNumber = (currentNumber * 10) + (currentChar - '0');
            }
            if ((!Character.isDigit(currentChar) && Character.isWhitespace(currentChar)) || i == length - 1) {
                switch (operation) {
                    case '-':
                        stack.push(-currentNumber);
                        break;
                    case '+':
                        stack.push(currentNumber);
                        break;
                    case '*':
                        stack.push(stack.pop() * currentNumber);
                        break;
                    case '/':
                        stack.push(stack.pop() / currentNumber);
                        break;
                    default:
                        break;
                }
                operation = currentChar;
                currentNumber = 0;
            }
        }

        int result = 0;
        while(!stack.isEmpty()){
            result += stack.pop();
        }

        return result;
    }
}

Approach 2: Optimised Approach without the stack

class Solution {
    public int calculate(String s) {
        if(s == null || s.isEmpty())
            return 0;
        int length = s.length();
        int currentNumber = 0, lastNumber = 0, result = 0;
        char operation = '+';
        for (int i = 0; i < length; i++) {
            char currentChar = s.charAt(i);
            if(Character.isDigit(currentChar)){
                currentNumber = (currentNumber * 10) + (currentChar - '0');
            }
            if((!Character.isDigit(currentChar) && !Character.isWhitespace(currentChar)) || i == length - 1){
                if(operation == '+' || operation == '-'){
                    result += lastNumber;
                    lastNumber = (operation == '+') ? currentNumber : -currentNumber;
                }else if(operation == '*'){
                    lastNumber = lastNumber * currentNumber;
                }else if(operation == '/'){
                    lastNumber = lastNumber / currentNumber;
                }
                operation = currentChar;
                currentNumber = 0;
            }
        }

        result += lastNumber;
        return result;
    }
}
224. Basic Calculator

Approach 1: Stack and String Reversal

import java.util.Stack;

class Solution {
    public int calculate(String s) {
        int operand = 0;
        int n = 0;
        Stack<Object> stack = new Stack<>();
        for (int i = s.length() - 1; i >= 0 ; i--) {
            char ch = s.charAt(i);
            if(Character.isDigit(ch)){
                operand = (int)Math.pow(10, n) * (int)(ch - '0') + operand;
                n++;
            }else if(ch != ' '){
                if(n != 0){
                    stack.push(operand);
                    n = 0;
                    operand = 0;
                }
                if(ch == '('){
                    int res = evaluateExpr(stack);
                    stack.pop();
                    stack.push(res);
                }else {
                    stack.push(ch);
                }
            }
        }
        if(n != 0){
            stack.push(operand);
        }

        return evaluateExpr(stack);
    }

    private int evaluateExpr(Stack<Object> stack){
        int res = 0;
        if(!stack.empty()){
            if(stack.peek() instanceof  Integer)
                res = (int)stack.pop();
            else{
                res = ((char)stack.pop() == '+' ? 1 : -1) * (int)stack.pop();
            }
        }
        while(!stack.empty() && !((char)stack.peek() == ')')){
            char sign = (char)stack.pop();
            if(sign == '+'){
                res += (int)stack.pop();
            }else{
                res -= (int)stack.pop();
            }
        }

        return res;
    }
}

移除重复的字符

316. Remove Duplicate Letters
class Solution {
    public String removeDuplicateLetters(String s) {
        int len = s.length();
        int[] lastIndex = new int[26];
        boolean[] seen = new boolean[26];
        for (int i = 0; i < len; i++) {
            lastIndex[s.charAt(i) - 'a'] = i;
        }

        Stack<Integer> st = new Stack<>();
        for (int i = 0; i < len; i++) {
            int index = s.charAt(i) - 'a';
            if(seen[index])
                continue;
            while(!st.isEmpty() && st.peek() > index && i < lastIndex[st.peek()]){
                seen[st.pop()] = false;
            }
            st.push(index);
            seen[index] = true;
        }

        StringBuilder builder = new StringBuilder();
        for(int index : st){
            builder.append((char)(index + 'a'));
        }

        return builder.toString();
    }
}

判断先序遍历的有效性

331. Verify Preorder Serialization of a Binary Tree

Approach 1 : Using Stack

class Solution {
    public boolean isValidSerialization(String preorder) {
        Stack<String> st = new Stack<>();
        String[] strs = preorder.split(",");
        for (int i = 0; i < strs.length; i++) {
            String str = strs[i];

            while (str.equals("#") && !st.isEmpty() && st.peek().equals("#")) {
                st.pop();
                if (st.isEmpty()) {
                    return false;
                } else {
                    st.pop();
                }
                st.push(str);
            }
        }
        return st.size() == 1 && st.peek().equals("#");
    }
}

Approach 2 : 7 lines Easy Java Solution

public boolean isValidSerialization(String preorder) {
    String[] nodes = preorder.split(",");
    int diff = 1;
    for (String node: nodes) {
        if (--diff < 0) return false;
        if (!node.equals("#")) diff += 2;
    }
    return diff == 0;
}

处理网状问题

341. Flatten Nested List Iterator
public class NestedIterator implements Iterator<Integer> {
    private List<Integer> list = new ArrayList<>();
    private int next, size;
    public NestedIterator(List<NestedInteger> nestedList) {
        Stack<NestedInteger> st = new Stack<>();
        for (int i = nestedList.size() - 1; i >= 0 ; i--) {
            st.push(nestedList.get(i));
        }
        while(!st.isEmpty()){
            NestedInteger current = st.pop();
            if(current.isInteger()){
                list.add(current.getInteger());
            }else{
                List<NestedInteger> nestedIntegers = current.getList();
                for (int i = nestedIntegers.size() - 1; i >= 0; i--) {
                    st.push(nestedIntegers.get(i));
                }
            }
        }

        size = list.size();
    }

    @Override
    public Integer next() {
        return list.get(next++);
    }

    @Override
    public boolean hasNext() {
        return next < size;
    }
}
385. Mini Parser
class Solution {
    public NestedInteger deserialize(String s) {
        Stack<Object> st = new Stack<>();
        int start = 0, i;
        for (i = 0; i < s.length(); i++) {
            char currentChar = s.charAt(i);
            if(currentChar == '['){
                st.push(currentChar);
                start = i + 1;
            }else if(currentChar == ','){
                if(start != i){
                    int value = Integer.parseInt(s.substring(start, i));
                    st.push(new NestedInteger(value));
                }
                start = i + 1;
            }else if(currentChar == ']'){
                if(start != i){
                    int value = Integer.parseInt(s.substring(start, i));
                    st.push(new NestedInteger(value));
                }

                NestedInteger cur = new NestedInteger();
                List<NestedInteger> list = new ArrayList<>();
                while(!st.isEmpty() && !(st.peek() instanceof Character)){
                    list.add(0, (NestedInteger)st.pop());
                }
                for (NestedInteger ni : list) {
                    cur.add(ni);
                }

                st.pop();
                st.push(cur);
                start = i + 1;
            }else
                ;
        }
        if(start != i){
            int value = Integer.parseInt(s.substring(start, i));
            st.push(new NestedInteger(value));
        }

        return (NestedInteger)st.pop();
    }
}
565. Array Nesting
class Solution {
    public int arrayNesting(int[] nums) {
        int n = nums.length;
        boolean[] visited = new boolean[n];
        int res = 0;
        for (int i = 0; i < n; i++) {
            if(visited[i])
                continue;
            else{
                Stack<Integer> st = new Stack<>();
                int cur = i;
                while(!visited[cur]){
                    st.push(cur);
                    visited[cur] = true;
                    cur = nums[cur];
                }

                res = Math.max(res, st.size());
            }
        }
        return res;
    }
}

不知道怎么描述的问题

456. 132 Pattern
class Solution {
    public boolean find132pattern(int[] nums) {
        if(nums == null || nums.length < 3)
            return false;
        int len = nums.length;
        for (int j = 0, min = Integer.MAX_VALUE; j < len; j++) {
            min = Math.min(nums[j], min);
            if(min == nums[j])
                continue;
            for (int k = len - 1; k > j; k--) {
               if(min < nums[k] && nums[k] < nums[j])
                   return true;
            }
        }

        return false;
    }
}
class Solution {
    public boolean find132pattern(int[] nums) {
        if(nums == null || nums.length < 3)
            return false;
        int len = nums.length;
        int[] arr = Arrays.copyOf(nums, len);
        for (int i = 1; i < len; i++) {
            arr[i] = Math.min(nums[i - 1], arr[i - 1]);
        }

        for (int j = len - 1, top = len; j >= 0; j--) {
            if(nums[j] <= arr[j])
                continue;
            while(top < len && arr[top] <= arr[j])
                top++;
            if(top < len && nums[j] > arr[top])
                return true;
            arr[--top] = nums[j];
        }
        
        return false;
    }
}
880. Decoded String at Index

Approach 1: Work Backwards

class Solution {
    public String decodeAtIndex(String S, int K) {
        long size = 0;
        int n = S.length();
        for (int i = 0; i < n; i++) {
            char c = S.charAt(i);
            if(Character.isDigit(c)){
                size *= c - '0';
            }else
                size++;
        }

        for (int i = n - 1; i >= 0; i--) {
            char c = S.charAt(i);
            K %= size;
            if(K == 0 && Character.isLetter(c)){
                return Character.toString(c);
            }
            if(Character.isDigit(c)){
                size /= c - '0';
            }
            else
                size--;
        }
        
        throw null;
    }
}
907. Sum of Subarray Minimums

Approach 1: Prev/Next Array

class Solution {
    private final static int modulo = (int)Math.pow(10, 9) + 7;

    public int sumSubarrayMins(int[] arr) {
        int n = arr.length;

        Stack<Integer> stack = new Stack<>();
        int[] prev = new int[n];
        for (int i = 0; i < n; i++) {
            while(!stack.isEmpty() && arr[i] <= arr[stack.peek()])
                stack.pop();
            prev[i] = stack.isEmpty() ? -1 : stack.peek();
            stack.push(i);
        }

        stack = new Stack<>();
        int[] next = new int[n];
        for (int k = n - 1; k >= 0 ; k--) {
            while(!stack.isEmpty() && arr[k] < arr[stack.peek()])
                stack.pop();
            next[k] = stack.isEmpty() ? n : stack.peek();
            stack.push(k);
        }

        long ans = 0;
        for (int i = 0; i < n; i++) {
            ans += (i - (long)prev[i]) * ((long)next[i] - i) % modulo * arr[i] % modulo;
            ans %= modulo;
        }

        return (int)ans;
    }
}

Next Greater Element

496. Next Greater Element I
class Solution {
    public int[] nextGreaterElement(int[] nums1, int[] nums2) {
        Map<Integer, Integer> map = new HashMap<>();
        Stack<Integer> st = new Stack<>();
        
        for(int num : nums2){
            if(st.isEmpty()){
                st.push(num);
            }else{
                while(!st.isEmpty() && st.peek() < num){
                    map.put(st.pop(), num);
                }
                st.push(num);
            }
        }
        
        int[] res = new int[nums1.length];
        Arrays.fill(res, -1);
        for (int i = 0; i < nums1.length; i++) {
            if(map.containsKey(nums1[i])){
                res[i] = map.get(nums1[i]);
            }
        }
        
        return res;
    }
}
503. Next Greater Element II
class Solution {
    public int[] nextGreaterElements(int[] nums) {
        int n = nums.length;
        int[] arr = new int[n * 2];
        for (int i = 0; i < n; i++) {
            arr[i] = nums[i];
            arr[n + i] = nums[i];
        }
        int[] res = new int[n];
        Arrays.fill(res, -1);
        Stack<int[]> st = new Stack<>();
        for (int i = 0; i < 2 * n; i++) {
            while(!st.isEmpty() && st.peek()[0] < arr[i]){
                res[st.pop()[1]] = arr[i];
            }
            st.push(new int[]{arr[i], i < n ? i : i - n});
        }
        
        return res;
    }
}
556. Next Greater Element III
class Solution {
    public int nextGreaterElement(int n) {
        char[] chars = String.valueOf(n).toCharArray();
        int len = chars.length;
        int j;
        for (j = len - 2; j >= 0 ; j--) {
            if(chars[j] < chars[j + 1])
                break;
        }
        if(j < 0)
            return -1;
        else{
            int i;
            for (i = len - 1; i > j; i--) {
                if(chars[j] < chars[i])
                    break;
            }
            char tmp = chars[j];
            chars[j] = chars[i];
            chars[i] = tmp;
            char[] chs = Arrays.copyOfRange(chars, j + 1, len);
            Arrays.sort(chs);
            for (i = 0; i < chs.length; i++) {
                chars[j + 1 + i] = chs[i];
            }

            long l = Long.parseLong(String.valueOf(chars));
            return l > Integer.MAX_VALUE ? -1 : (int)l;
        }
    }
}
739. Daily Temperatures
class Solution {
    public int[] dailyTemperatures(int[] T) {
        int n = T.length;
        int[] res = new int[n];
        Stack<int[]> st = new Stack<>();

        for (int i = 0; i < n; i++) {
            while(!st.isEmpty() && st.peek()[0] < T[i]){
                int[] top = st.pop();
                res[top[1]] = i - top[1];
            }
            st.push(new int[]{T[i], i});
        }
        
        return res;
    }
}
726. Number of Atoms

Approach 1 : Using Stack

class Solution {
    public String countOfAtoms(String formula) {
        Stack<Object> st = new Stack<>();
        List<Object> objects = parse(formula);
        for (Object object : objects) {
            if (object instanceof Character && (Character)object == ')'){
                List<Object> list = new ArrayList<>();
                while(!(st.peek() instanceof Character && (Character)st.peek() == '(')){
                    list.add(0, st.pop());
                }
                st.pop();
                Map<String, Integer> cal = cal(list);
                st.push(cal);
            } else if(object instanceof Integer){
                if(st.peek() instanceof Map){
                    Map<String, Integer> map = (Map<String, Integer>) st.pop();
                    int n = (Integer)object;
                    for (Map.Entry<String, Integer> entry : map.entrySet()) {
                        map.put(entry.getKey(), entry.getValue() * n);
                    }
                    st.push(map);
                }else
                    st.push(object);
            }
            else
                st.push(object);
        }

        Map<String, Integer> m = cal(Arrays.asList(st.toArray()));

        StringBuilder builder = new StringBuilder();
        for (Map.Entry<String, Integer> entry : m.entrySet()) {
            builder.append(entry.getKey());
            if(entry.getValue() > 1){
                builder.append(entry.getValue());
            }
        }

        return builder.toString();
    }

    private Map<String, Integer> cal(List<Object> list){
        Map<String, Integer> res = new TreeMap<>();
        int index = 0, len = list.size();
        while(index < len){
            Object obj = list.get(index);
            if(obj instanceof String){
                String key = (String)obj;
                int count = 1;
                if(index + 1 < len && list.get(index + 1) instanceof Integer){
                    count = (int) list.get(index + 1);
                    index++;
                }
                res.put(key, res.getOrDefault(key, 0) + count);
            }else if(obj instanceof Map){
                Map<String, Integer> map = (Map<String, Integer>) obj;
                for (Map.Entry<String, Integer> entry : map.entrySet()) {
                    res.put(entry.getKey(), res.getOrDefault(entry.getKey(), 0) + entry.getValue());
                }
            }else;
            index++;
        }
        
        return res;
    }
    
    private List<Object> parse(String formula){
        List<Object> res = new LinkedList<>();
        int s = -1, len = formula.length();
        int flag = -1; // -1 invalid, 0 element, 1 count
        for (int i = 0; i < len; i++) {
            char ch = formula.charAt(i);
            if(Character.isDigit(ch)){
                if(flag == -1){
                    flag = 1;
                    s = i;
                }else if(flag == 0){
                    res.add(formula.substring(s, i));
                    flag = 1;
                    s = i;
                }else
                    ;
            }else if(Character.isUpperCase(ch)){
                if(flag == -1){
                    flag = 0;
                    s = i;
                }else if(flag == 1){
                    res.add(Integer.parseInt(formula.substring(s, i)));
                    flag = 0;
                    s = i;
                }else {
                    res.add(formula.substring(s, i));
                    flag = 0;
                    s = i;
                }
            }else if(ch == '(' || ch == ')'){
                if(flag == -1){
                    res.add(ch);
                    s = -1;
                }else if(flag == 0){
                    res.add(formula.substring(s, i));
                    flag = -1;
                    s = -1;
                    res.add(ch);
                }else if(flag == 1){
                    res.add(Integer.parseInt(formula.substring(s, i)));
                    flag = -1;
                    s = -1;
                    res.add(ch);
                }else
                    ;
            }else
                ;
        }

        if(flag == 0) {
            res.add(formula.substring(s));
        }else if(flag == 1){
            res.add(Integer.parseInt(formula.substring(s)));
        }

        return res;
    }
}

Remove elements

402. Remove K Digits

Approach 1

class Solution {
    public String removeKdigits(String num, int k) {
        if(k == 0){
            while(num.length() > 0 && num.charAt(0) == '0')
                num = num.substring(1);
            return num.length() == 0 ? "0" : num;
        }

        int j = 0;
        for (; j + 1 < num.length(); j++) {
            if(num.charAt(j) > num.charAt(j + 1))
                break;
        }

        String s;
        if(j == 0)
            s = num.substring(1);
        else if (j == num.length() - 1)
            s = num.substring(0, num.length() - 1);
        else
            s = num.substring(0, j) + num.substring(j + 1);

        return removeKdigits(s, k - 1);
    }
}

Approach 2 : Using Stack

class Solution {
    public String removeKdigits(String num, int k) {
        int len = num.length();
        if(k == len)
            return "0";
        Stack<Character> stack = new Stack<>();
        int i = 0;
        while(i < len){
            while(k > 0 && !stack.isEmpty() && stack.peek() > num.charAt(i)){
                stack.pop();
                k--;
            }
            stack.push(num.charAt(i));
            i++;
        }

        //covering case like "1111"
        while(k > 0){
            stack.pop();
            k--;
        }

        StringBuilder builder = new StringBuilder();
        for (Character character : stack) {
            builder.append(character);
        }

        while(builder.length() > 1 && builder.charAt(0) == '0')
            builder.deleteCharAt(0);
        
        return builder.toString();
    }
}
1081. Smallest Subsequence of Distinct Characters
class Solution {
    public String smallestSubsequence(String s) {
        int[] lastIdxes = new int[26];
        boolean[] visited = new boolean[26];
        char[] chs = s.toCharArray();
        for (int i = 0; i < chs.length; i++) {
            lastIdxes[chs[i] - 'a'] = i;
        }

        Stack<Character> stack = new Stack<>();
        int index = 0;
        for (int i = 0; i < chs.length; i++) {
            char ch = chs[i];
            index = ch - 'a';
            if(visited[index])
                continue;
            while(!stack.isEmpty() && ch < stack.peek() && lastIdxes[stack.peek() - 'a'] > i)
                visited[stack.pop() - 'a'] = false;
            stack.push(ch);
            visited[index] = true;
        }

        StringBuilder builder = new StringBuilder();
        for (Character character : stack) {
            builder.append(character);
        }

        return builder.toString();
    }
}
1673. Find the Most Competitive Subsequence
class Solution {
    public int[] mostCompetitive(int[] nums, int k) {
        Stack<Integer> stack = new Stack<>();
        int[] result = new int[k];
        for (int i = 0; i < nums.length; i++) {
            while(!stack.empty() && nums[i] < nums[stack.peek()] && nums.length - i + stack.size() > k){
                stack.pop();
            }
            
            if(stack.size() < k){
                stack.push(i);
            }
        }

        for (int i = k - 1; i >= 0; i--) {
            result[i] = nums[stack.pop()];
        }
        
        return result;
    }
}