例
如給定‘asdsdss’ 字符s出現4次,d出現2次,a出現一次,打印結果應爲:ssssdda
以下是解體過程
package com.example.demo;
import java.util.*;
public class Deni {
public static void main(String[] args) {
String s = "aaffaawnnnwqqqoooooooqrrrrllllllllllrd";
char[] chars = s.toCharArray();
// 使用map統計字符出現的個數
HashMap<Character, Integer> map = countCharMap(chars);
Integer[] objects = map.values().toArray(new Integer[0]);
// 首先排序
quickSort(objects, 0, objects.length - 1);
// 然後按照從大到小排序順序組裝字符
combineCharBySort(chars, map, objects);
// 打印組裝好的字符
for (int i = 0; i < chars.length; i++) {
System.out.print(chars[i]);
}
System.out.println();
}
/**
* 使用map統計字符出現的次數
* @param chars 字符數組
* @return map
*/
private static HashMap<Character, Integer> countCharMap(char[] chars) {
HashMap<Character, Integer> map = new HashMap();
for (char aChar : chars) {
if (map.get(aChar) == null) {
map.put(aChar, 1);
}else{
map.put(aChar, map.get(aChar) + 1);
}
}
return map;
}
/**
* 組裝要打印的字符數組
* @param chars 字符數組
* @param map map
* @param objects 從大到小排序好的每個字符出現的個數
*/
private static void combineCharBySort(char[] chars, HashMap<Character, Integer> map, Integer[] objects) {
// 要存入的字符串下標
int j = 0;
for (int i = 0; i < objects.length - 1; i++) {
for (Map.Entry<Character, Integer> characterIntegerEntry : map.entrySet()) {
Character key = characterIntegerEntry.getKey();
Integer value = characterIntegerEntry.getValue();
if (value.equals(objects[i])) {
int count = j;
// 將當前相同的字符挨個存入數組
while (j - count < value) {
chars[j++] = key;
}
// 遍歷過的字符從map中移除,降低遍歷次數
map.remove(key);
break;
}
}
}
}
/**
* 快速排序
* @param arr 數組
* @param left 數組左下標
* @param right 數組右下標
*/
private static void quickSort(Integer[] arr, int left, int right){
if (left >= right) {
return;
}
// 排序並獲取中間值(基準值)的下標
// int mid = getMid(arr, left, right);
int mid = getMid2(arr, left, right);
// 遞歸排序左邊的區間,注意:最後一位參數不能寫成mid,否則會死循環
quickSort(arr, left, mid - 1);
// 遞歸排序右邊的區間,中間的參數不能寫爲mid,否則會死循環
quickSort(arr, mid + 1, right);
}
/**
* 查找基準下標(巧妙使用數組下標排序)
* @param arr 數組
* @param left 左下標
* @param right 右下標
* @return 中值下標
*/
private static int getMid2(Integer[] arr, int left, int right){
int i = left;
int pivot = arr[right];
for (int j = left; j < right; j++) {
if (arr[j] > pivot) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
i++;
}
}
int temp = arr[i];
arr[i] = arr[right];
arr[right] = temp;
return i;
}
/**
* 查到基準下標(排序)
* @param arr 數組
* @param left 數組左下標
* @param right 數組右下標
* @return 中值下標
*/
private static int getMid(Integer[] arr, int left, int right) {
int base = arr[left];
while (left < right){
// 從最右邊開始查找小於基準點點值,如沒有就將最右邊的下標減1
// (注意:判斷條件必須是包含等於,否吃會死循環,因此快速排序不能保證兩個等值的元素,排完循序後還保持原有循序,不是穩定的排序算法)
while (left < right && arr[right] >= base) {
right--;
}
// 找到小於基準點點值後交換
arr[left] = arr[right];
// 從左邊開始查找大於基準值的元素,沒有就將下標加1
while (left < right && arr[left] <= base){
left++;
}
// 找到大於基準點的值後交換
arr[right] = arr[left];
}
// 最後將原來的基準值填充回來,此時的left就是基準值的下標(注意:left經過++操作已經不是原來的下標值了)
arr[left] = base;
return left;
}
}