輸入一個正整數數組,把數組裏全部數字拼接起來排成一個數,打印能拼接出的全部數字中最小的一個。例如輸入數組{3,32,321},則打印出這三個數字能排成的最小數字爲321323。java
此題的目的是如何找到這些數的全部的排列中最小的字典序的那一個排列。因此問題轉化爲如何找到字典序最小的排列。爲了防止組成的數溢出,下面統一轉換爲字符串來作。。算法
既然須要找到字典序最小的哪一個排列,那麼咱們乾脆一不作二不休,我求出全部的排列組合,而後排序後取最小不就得了。進一步轉化問題爲全排列問題,只不過參與排列的元素爲字符串了,而不在是單純的單個字符。
求全排列的算法我已經在這篇博客寫的很清楚了。如下內容爲那篇博客裏最優的求全排列的解法,包含如何對於重複元素的處理防止沒必要要的處理操做。
能夠把排列問題分紅固定第一個位置,剩餘元素全排列問題。以後對剩餘元素又進行一樣的處理,固定第一個位置,剩餘元素全排列。如圖: 數組
public static String PrintMinNumber(int [] numbers) {
if(numbers == null || numbers.length == 0) {
return "";
}
List<String> result = new ArrayList<>();
getAllCombine(0, numbers, result);
Collections.sort(result);
return result.get(0);
}
private static void getAllCombine(int index, int[] numbers, List<String> result) {
if(index == numbers.length - 1) {
StringBuilder sb = new StringBuilder();
for(int num : numbers) {
sb.append(num);
}
result.add(sb.toString());
return;
}
//記錄已經出現第一部分的元素
Set<Integer> ocur = new HashSet<>();
for(int i = index; i < numbers.length; i++) {
if(!(i != index && ocur.contains(numbers[i]))) {
ocur.add(numbers[i]);
swap(numbers, i, index);
getAllCombine(index + 1, numbers, result);
swap(numbers, i, index);
}
}
}
public static void swap(int[] temp, int i, int j) {
if(i != j) {
int str = temp[i];
temp[i] = temp[j];
temp[j] = str;
}
}
複製代碼
思路一的複雜度爲O(n!),那麼咱們能不能不進行全排列就能找到那個特定的排列呢?很容易想到就是排序,若是能想到一個很好的排序策略,便可優雅獲得最後的結果。
對於給定的2個數,a和b。如何肯定二者之間的排序策略呢?咱們能夠發現這二者的排列爲:ab,ba。咱們最終目的是找到字典序最小的那個排列,因此咱們確定應該保持這種關係,從而決定是否交換順序:app
不理解的話,能夠結合選擇排序算法來理解,咱們在n個元素選擇出最小的做爲左邊的值,顯然它應該位於全部n-1個元素的左邊,也就是第一個位置上。接着在n-1個元素找到次最小,反覆如此,直到沒有剩餘元素。
若是你理解了選擇排序的作法,又由於通常的排序算法的結果都是同樣,因此咱們能夠採用更快的排序算法來解答此題,爲了方便,直接了使用了庫函數,固然你能夠自行實現快速排序或歸併排序,這些都何嘗不可。ide
public static String PrintMinNumber2(int [] numbers) {
if(numbers == null || numbers.length == 0) {
return "";
}
String[] strNumbers = new String[numbers.length];
for(int i = 0; i < numbers.length; i++) {
strNumbers[i] = String.valueOf(numbers[i]);
}
Arrays.sort(strNumbers, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return (o1 + o2).compareTo(o2 + o1);
}
});
StringBuilder sb = new StringBuilder();
for(int i = 0; i < strNumbers.length; i++) {
sb.append(strNumbers[i]);
}
return sb.toString();
}
複製代碼
對於給定一組數,讓求特定的排列時,這時確定能夠用全排列來作,只不過涉及到效率問題。進一步優化則能夠往深處深究。函數