最近在工作中遇到个打乱算法,需求是一个字符串集合,经过排序后,需要让相邻两个元素的值不同。
这里我将该算法分享出来,如果有性能更好的算法,也请大伙一起做个分享,也顺带当做笔记记录下来。
public static void main(String[] args) {
List<String> ss = Arrays.asList("1", "1", "1", "1", "1", "1", "1", "1", "1", "1",
"2", "2", "2", "2", "2",
"3", "3", "3", "3", "3", "3", "3");
System.out.println("未乱序集合" + ss);
//先对集合元素进行分组,key为元素值,value为对应的元素集合
Map<String, List<String>> map = new HashMap<>();
for (String s : ss) {
List<String> list = map.get(s);
if(list == null) {
list = new ArrayList<>();
map.put(s, list);
}
list.add(s);
}
//再对上面的map进行处理,生成一个key为每个元素的数量,value为相同数量的元素集合的countMap
Map<Integer,List<String>> countMap = new HashMap<>();
for (Map.Entry<String, List<String>> entry : map.entrySet()) {
Integer count = entry.getValue().size();
List<String> list = countMap.get(count);
if(list == null) {
list = new ArrayList<>();
countMap.put(count, list);
}
list.add(entry.getKey());
}
List<String> allocateList = new ArrayList<>(ss.size());
allocate(allocateList, countMap, map, "");
System.out.println("乱序后集合" + ss);
}
/**
*
* @param allocateList 乱序元素集合
* @param countMap <元素数量,元素列表>
* @param map <元素,元素列表>
* @param lastElementKey 上一个放入乱序集合的元素值,用来避免元素重复
*/
private static void allocate(List<String> allocateList, Map<Integer, List<String>> countMap, Map<String, List<String>> map, String lastElementKey) {
if(countMap.size() == 1 && countMap.containsKey(0)) {
return;
}
ArrayList<Integer> sorted = new ArrayList<>(countMap.keySet());
Collections.sort(sorted, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2.compareTo(o1);
}
});
//乱序的时候优使用数量最多的元素
Integer countKey = sorted.get(0);
List<String> elementList = countMap.get(countKey);
String key = elementList.get(0);
if(Objects.equals(key, lastElementKey)) {
Integer alternativeCountKey = sorted.get(1);
if(alternativeCountKey != 0) {
countKey = alternativeCountKey;
elementList = countMap.get(countKey);
key = elementList.get(0);
}
}
elementList.remove(key);
if(elementList.size() == 0) {
countMap.remove(countKey);
}
List<String> list = map.get(key);
if(Objects.equals(key, lastElementKey)) {
throw new RuntimeException("无法进行,请减少key为" + key + "的元素数量" + list.size() + "个");
}
String remove = list.remove(0);
List<String> idList = countMap.get(list.size());
if(idList == null) {
idList = new ArrayList<>();
countMap.put(list.size(), idList);
}
idList.add(key);
lastElementKey = key;
allocateList.add(remove);
allocate(allocateList, countMap, map, lastElementKey);
}
自己瞎画的一个图解,也不知道能不能解释清楚,大家凑合看吧。手动滑稽