// I recommend this solution: just need map to keep the mapping relationship
    public boolean wordPattern(String pattern, String str) {
        if (pattern == null || pattern.length() == 0 || str == null || str.length() == 0) {
            return false;
        }

        String[] strs = str.trim().split(" ");

        if (pattern.length() != strs.length) {
            return false;
        }

        Map<Character, String> lookup = new HashMap<>();
        // As it says, it is a bijection, so it needs to be 1 to 1 mapping, cannot exist a case one key maps to different value case
        // E.g., need this set for abba, dog dog dog dog -> false case
        Set<String> mapped = new HashSet<>(); 

        for (int i = 0; i < pattern.length(); i++) {
            char c = pattern.charAt(i);

            if (lookup.containsKey(c)) {
                if (!lookup.get(c).equals(strs[i])) {
                    return false;
                }
            } else {
                // shit, just know put actually returns a V, which is the previous value, or null if not exist (or an associated null value)
                lookup.put(c, strs[i]);
                if (mapped.contains(strs[i])) {
                    return false;
                }
                mapped.add(strs[i]);
            }
        }

        return true;
    }