liuzhch1

LeetCode 726: 原子的数量-栈和Map的结合以及字符串处理 | Number of Atoms-Combination of stack, map and string processing

Problem link: 726. Number of Atoms

Problem Description

Give a chemical formula, return the count of each atom.

  • The count after atom only writes if it's more than 1
  • A formula placed in parentheses, and a count after the right parenthesis(maybe not) is also a formula: (H2O2), (H2O)2
  • The atom in the returned string should in lexicographic order

Example:

Input: formula = "Mg(OH)2"
Output: "H2MgO2"

Problem Analysis

It is obvious that the difficulty in this problem is to remove the parentheses.
Each atom inside a parentheses, needs to multiple the count outside the parentheses. Because the number of atoms in this parentheses needs to be multipled by, and each atom has its corresponding count. So we can abstract the content inside each parentheses as a map.
So an outer parentheses may contains may inner parentheses inside: (Fe2(SO4)3)2, so we can regard the inner parentheses part SO4 as a innerMap, the outer Fe2(innerMap)3 as the outer map.
We can go through from left to right

  • If comes a (, then we create a new inner map
  • If comes an atom, then we record its number in the inner map
  • If comes a ), then we open the inner map, multiple each atom number with the number comes after )(if no number following, just multiple 1). And finally, merge the multipled inner map to the outer map.

And the outer map multipled and merge to the outer's outer map, and etc.

So we can use a stack whose elements are maps to solve this problem.

String formula;
int idx, len;

public String countOfAtoms(String fml) {
    this.formula = fml; // the chemical formula
    this.idx = 0; // the index we are handling
    this.len = formula.length();
    // create the map stack
    Deque<Map<String, Integer>> stack = new ArrayDeque<>();
    // default map containing atoms outside any parentheses, eg:`Fe` in `Fe2(SO4)3`
    stack.push(new HashMap<String, Integer>());
    while (idx < len) {
        switch (formula.charAt(idx)) {
            case '(':
                // create a new inner map to hold atoms inside the parenthese
                stack.push(new HashMap<String, Integer>());
                idx++;
                break;
            case ')':
                idx++;
                Map<String, Integer> innerMap = stack.pop();
                Map<String, Integer> outerMap = stack.peek();
                int cnt = nextNum();
                // multiple the inner cnt with the )n's n, and join to the outerMap
                for (String s : innerMap.keySet()) {
                    outerMap.put(s, outerMap.getOrDefault(s, 0) + innerMap.get(s) * cnt);
                }
                break;
            default:
                // atom
                // record this atom's number
                Map<String, Integer> map = stack.peek();
                String atom = nextAtom();
                int n = nextNum();
                map.put(atom, map.getOrDefault(atom, 0) + n);
        }
    }
    // turn outest map to a treeMap so that the atom name is ordered
    TreeMap<String, Integer> treeMap = new TreeMap<>(stack.peek());
    StringBuilder sb = new StringBuilder();
    for (String s : treeMap.keySet()) {
        sb.append(s);
        int cnt = treeMap.get(s);
        if (cnt > 1) {
            sb.append(String.valueOf(cnt));
        }
    }
    return sb.toString();
}

String Processing

Meanwhile, we need to handle each atom's name and next number. Java support useful functions to easily reach the goal:

Get next atom's name

private String nextAtom() {
    int start = idx++;
    // continue matching while next character is a lowercase character
    while (idx < len && Character.isLowerCase(formula.charAt(idx))) {
        idx++;
    }
    return formula.substring(start, idx);
}

Get next number

private int nextNum() {
    // If the following is not a number, return the default 1
    if (idx == len || !Character.isDigit(formula.charAt(idx))) {
        return 1;
    }
    int start = idx++;
    // continue matching while next character is a digit
    while (idx < len && Character.isDigit(formula.charAt(idx))) {
        idx++;
    }
    return Integer.parseInt(formula.substring(start, idx));
}
Complete code:
class Solution{
    String formula;
    int idx, len;

    public String countOfAtoms(String fml) {
        this.formula = fml; // the chemical formula
        this.idx = 0; // the index we are handling
        this.len = formula.length();
        // create the map stack
        Deque<Map<String, Integer>> stack = new ArrayDeque<>();
        // default map containing atoms outside any parentheses, eg:`Fe` in `Fe2(SO4)3`
        stack.push(new HashMap<String, Integer>());
        while (idx < len) {
            switch (formula.charAt(idx)) {
                case '(':
                    // create a new inner map to hold atoms inside the parenthese
                    stack.push(new HashMap<String, Integer>());
                    idx++;
                    break;
                case ')':
                    idx++;
                    Map<String, Integer> innerMap = stack.pop();
                    Map<String, Integer> outerMap = stack.peek();
                    int cnt = nextNum();
                    // multiple the inner cnt with the )n's n, and join to the outerMap
                    for (String s : innerMap.keySet()) {
                        outerMap.put(s, outerMap.getOrDefault(s, 0) + innerMap.get(s) * cnt);
                    }
                    break;
                default:
                    // atom
                    // record this atom's number
                    Map<String, Integer> map = stack.peek();
                    String atom = nextAtom();
                    int n = nextNum();
                    map.put(atom, map.getOrDefault(atom, 0) + n);
            }
        }
        // turn outest map to a treeMap so that the atom name is ordered
        TreeMap<String, Integer> treeMap = new TreeMap<>(stack.peek());
        StringBuilder sb = new StringBuilder();
        for (String s : treeMap.keySet()) {
            sb.append(s);
            int cnt = treeMap.get(s);
            if (cnt > 1) {
                sb.append(String.valueOf(cnt));
            }
        }
        return sb.toString();
    }

    private String nextAtom() {
        int start = idx++;
        // continue matching while next character is a lowercase character
        while (idx < len && Character.isLowerCase(formula.charAt(idx))) {
            idx++;
        }
        return formula.substring(start, idx);
    }

    private int nextNum() {
        // If the following is not a number, return the default 1
        if (idx == len || !Character.isDigit(formula.charAt(idx))) {
            return 1;
        }
        int start = idx++;
        // continue matching while next character is a digit
        while (idx < len && Character.isDigit(formula.charAt(idx))) {
            idx++;
        }
        return Integer.parseInt(formula.substring(start, idx));
    }
}

posted on 2022-06-26 17:14  liuzhch1  阅读(11)  评论(0编辑  收藏  举报

导航