按频率排序字符串数组的最有效方法

时间:2013-09-06 14:51:06

标签: java arrays string mode

我有一个字符串数组:

String[] stringArray = {"x", "y", "z", "x", "x", "y", "a"};

按照每个Collection频率与频率的频率顺序排列为String的最快/最有效的方法是什么?

我虽然使用String作为HashMap<String,Integer>中的关键字,但这不会按频率排序

我考虑的其他方法是使用带有该整数的字符串列表的TreeMap<Integer, String[]>,但似乎涉及很多检查..

我试图避免使用多个循环如果可能,因为我的String数组将比上面的数组大得多。谢谢!

修改 我想要的只是能够按频率顺序输出字符串,并且最好能够将该字符串与其频率在数组中配对,例如两个输出数组:

["x", "y", "z", "a"]
[3,2,1,1]

如果速度不是问题,这将是一个非常简单的问题,这就是为什么我在这里问伟大的思想:)

7 个答案:

答案 0 :(得分:10)

您可以分两步解决此问题:

  1. 创建一个计数器对象 - 每个字符串的Map<String, Integer>列表,它在输入中出现的次数:换句话说,它是一个频率图。这是O(n),因为您只需要遍历输入一次以构建地图

  2. 使用上一个地图,创建一个包含其键的列表,使用项目的频率(地图中的值)作为排序标准进行排序。这是O(n log n),您可以使用Collections.sort()来调用Comparator,使用字符串频率进行比较

  3. 这就是我的意思:

    String[] stringArray = {"x", "y", "z", "x", "x", "y", "a"};
    
    final Map<String, Integer> counter = new HashMap<String, Integer>();
    for (String str : stringArray)
        counter.put(str, 1 + (counter.containsKey(str) ? counter.get(str) : 0));
    
    List<String> list = new ArrayList<String>(counter.keySet());
    Collections.sort(list, new Comparator<String>() {
        @Override
        public int compare(String x, String y) {
            return counter.get(y) - counter.get(x);
        }
    });
    

    执行上述代码后,变量list将包含以下值(未指定相同频率的元素之间的顺序):

    [x, y, a, z]
    

    将列表转换为数组非常简单:

    list.toArray(new String[list.size()])
    

    如果你需要找出每个字符串的频率,只需遍历排序的键:

    for (String str : list) {
        int frequency = counter.get(str);
        System.out.print(str + ":" + frequency + ", ");
    }
    

答案 1 :(得分:3)

使用HashMap<String,Integer>来维持您的计数。这将是处理任意字符串列表的最有效方法。

从地图ArrayList<Map.Entry<String,Integer>>创建entrySet()

使用Collections.sort()和自定义比较器对此列表进行排序。

不要挂在微优化上。

答案 2 :(得分:2)

如果第三方图书馆是公平的游戏,那么以下与番石榴的单行程是渐近最优的:

Multisets.copyHighestCountFirst(ImmutableMultiset.copyOf(array))
   .elementSet().toArray(new String[0]);

答案 3 :(得分:1)

String[] stringArray = {"x", "y", "z", "x", "x", "y", "a"};

List<String> list = Arrays.asList(stringArray);
Collections.sort(list);

HashMap<String, Integer> map = new HashMap<String, Integer>();

for(int i = 0; i < list.size();) {

    String s = list.get(i); //get the string to count

    int count = list.lastIndexOf(s) - list.indexOf(s) + 1; //count it

    map.put(s, count); // add it

    i = list.lastIndexOf(s) + 1; // skip to the next string

}

我认为这是一个优雅的解决方案,但我不知道它是多么高效。 如果您对它进行了排序,请使用TreeMap,但这确实很慢。

您可以像这样对其进行排序:

TreeMap<String, Integer> sortedMap = new TreeMap<String, Integer>(unsortedMap);

但请注意,将Integer作为键是行不通的! 因为一个键是唯一的,例如a和b出现一次,就会被踢掉!

答案 4 :(得分:1)

打印结果:    1)以desc顺序排序的具有不同出现的字符串。    2)具有相同出现的字符串按字符串按升序排序。

 public static void sortStringByOccurance(String[] stringArray) {
    // O(n)
    Map<String, Integer> map = new HashMap<>();
    for (String str : stringArray) {
        map.put(str, map.containsKey(str)? map.get(str)+1 : 1);
    }

    // O(n)
    TreeMap<Integer, TreeSet<String>> treemap = new TreeMap<>();
    for (String key : map.keySet()) {
        if (treemap.containsKey(map.get(key))) {
            treemap.get(map.get(key)).add(key);
        }
        else {
            TreeSet<String> set = new TreeSet<>();
            set.add(key);
            treemap.put(map.get(key), set);
        }
    }

    // O(n)
    Map<Integer, TreeSet<String>> result = treemap.descendingMap();
    for (int count : result.keySet()) {
        TreeSet<String> set = result.get(count);
        for (String word : set) {
            System.out.println(word + ":" + count);
        }
    }
}

答案 5 :(得分:0)

可以用最少的代码行:

String[] s = {"x", "y", "z", "x", "x", "y", "a"};
HashMap<String,Integer> hm = new HashMap<String,Integer>();
for(int i=0;i<s.length;i++){
    int count = hm.containsKey(s[i]) ? hm.get(s[i]) : 0;
    hm.put(s[i], count + 1);            
}

答案 6 :(得分:0)

另一种解决方案:

String[] s = {"x", "y", "z", "x", "x", "y", "a"};
HashMap<String,Integer> hm = new HashMap<String,Integer>();

for(int i=0;i<s.length;i++){
    hm.putIfAbsent(s[i], 0);
    hm.put(s[i], hm.get(s[i]) + 1);
}
System.out.println(hm);