Sort Characters By Frequency Java
You have conceived a theoretical model that works. And avoids sorting.


Tiers by frequency
Every tier contains letters of that frequency


It will come at no surprise, that moving a char from on frequency's bin to the next frequency's bin will cost at least as much as sorting. But it is a nice mechanism
one sees too rare, and might have its application in vector operations, GPUs or whatever.


Improved could be the names. "Tier" one inclines to love, and might be apt, but does the term help in understanding the code?
Use if possible more general interfaces implemented by specific classes, like List&lt;T&gt; list = new ArrayList&lt;&gt;();. This is more flexible, when passing to methods, reimplementing with another class.
The comment to remain is for adding null for the frequency 0.
For characters in a tier use a Set. As implementation I used a TreeSet which is sorted to give nicer output.
Use as index not i but rather freq.
Moving from one frequency to the next higher can be done in two separate steps old+new. That makes the code more readable.


so:

public static String frequencySort(String s) {
    if (s.length() &lt;= 1) return s;

    List&lt;Set&lt;Character&gt;&gt; charsByFrequency = new ArrayList&lt;&gt;(); // stores characters at their proper frequency "tier"
    Map&lt;Character, Integer&gt; frequencyMap = new HashMap&lt;&gt;(); // maps the characters to their current frequency tier
    charsByFrequency.add(null); // entry for frequency 0 is not used

    for (char c : s.toCharArray()) {
        Character ch = c; // Does ch = Character.valueOf(c);
        int oldFreq = frequencyMap.getOrDefault(c, 0);
        if (oldFreq != 0) {
            charsByFrequency.get(oldFreq).remove(ch);
        }
        int freq = oldFreq + 1;
        if (freq &gt;= charsByFrequency.size()) {
            charsByFrequency.add(new TreeSet());
        }
        charsByFrequency.get(freq).add(ch);
        frequencyMap.put(ch, freq);
    }

    StringBuilder result = new StringBuilder();
    for (int i = 1; i &lt; charsByFrequency.size(); i++) { // iterate through tiers
        Set&lt;Character&gt; tier = charsByFrequency.get(i); // get tier
        for (Character c : tier) { // for each char in tier, append to string a number of times equal to the tier
            for (int j = 0; j &lt; i; j++) result.append(c);
        }
    }

    result.reverse(); // reverse, since result is currently in ascending order
    return result.toString();
}