#資料結構與演算法學習筆記#劍指Offer30:把陣列排成最小的數 + 自定義比較器 + 測試用例(Java、C/C++)
阿新 • • 發佈:2018-12-13
2018.10.6
1.求全排列最小。事實上用全排列硬剛這道題確實是最直接的辦法,因為乍一眼看上去實在不好歸納數字之間的順序關係,全排列具體實現原理可以參考上述文章。
2.自定義比較器。為什麼說不好歸納數字之間的關係呢?比如{4,42,43,432},比如這四個數字如果要按照題目的要求排列,那結果應該是42-432-43-4,不存在直接的數字關係。因此可以先轉換為字串尋找思路,本題的比較規則是對拼接後的字串進行比較,即將str1+str2與str2+str1進行比較(可以進行嚴謹的數學證明),將所有元素由小到大進行排列然後拼接。
題目描述
輸入一個正整數陣列,把數組裡所有數字拼接起來排成一個數,列印能拼接出的所有數字中最小的一個。例如輸入陣列{3,32,321},則打印出這三個數字能排成的最小數字為321323。
Java實現:
/** * * @author ChopinXBP * 輸入一個正整數陣列,把數組裡所有數字拼接起來排成一個數,列印能拼接出的所有數字中最小的一個。 * 例如輸入陣列{3,32,321},則打印出這三個數字能排成的最小數字為321323。 * */ import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.TreeSet; public class PrintMinNumber_31 { public static void main(String[] args) { // TODO Auto-generated method stub int[] numbers = {4, 42, 4321, 43, 432}; System.out.println(PrintMinNumber1(numbers)); } //方法1:求全排列最小 public static String PrintMinNumber1(int [] numbers) { if(numbers == null)return null; ArrayList<String> numStr = new ArrayList<>(); for(int i = 0; i < numbers.length; i++){ String str = numbers[i] + ""; numStr.add(str); } TreeSet<String> strList = new TreeSet<>(); Solution(numStr, 0, strList); return strList.first(); } public static void Solution(ArrayList<String> numStr, int begin, TreeSet<String> strList){ if(begin == numStr.size()){ StringBuilder resultStr = new StringBuilder(); for(int i = 0; i < numStr.size(); i++){ resultStr.append(numStr.get(i)); } strList.add(resultStr.toString()); } for(int i = begin; i < numStr.size(); i++){ Tmp(numStr, i, begin); Solution(numStr, begin + 1, strList); Tmp(numStr, i, begin); } } public static void Tmp(ArrayList<String> numStr, int i, int j){ String tmp = numStr.get(i); numStr.set(i, numStr.get(j)); numStr.set(j, tmp); } //方法2:自定義比較器(用拼接後的字串比較) public static String PrintMinNumber2(int [] numbers) { if(numbers == null)return null; ArrayList<Integer> numStr = new ArrayList<>(); for(int i = 0; i < numbers.length; i++){ String str = numbers[i] + ""; numStr.add(Integer.parseInt(str)); } /* //這種方式定義比較器時間與空間效率均較低 Collections.sort(numStr, (Integer str1, Integer str2) -> Integer.compare(Integer.parseInt(str1 + "" + str2), Integer.parseInt(str2 + "" + str1))); */ Collections.sort(numStr, new Comparator<Integer>() { @Override public int compare(Integer num1, Integer num2){ String str1 = num1 + "" + num2; String str2 = num2 + "" + num1; return str1.compareTo(str2); } }); StringBuilder resultStr = new StringBuilder(); for(int i = 0; i < numStr.size(); i++){ resultStr.append(numStr.get(i)); } return resultStr.toString(); } }
C++實現示例(方法2):
class Solution { public: static bool cmp(int a,int b){ string A=""; string B=""; A+=to_string(a); A+=to_string(b); B+=to_string(b); B+=to_string(a); return A<B; } string PrintMinNumber(vector<int> numbers) { string answer=""; sort(numbers.begin(),numbers.end(),cmp); for(int i=0;i<numbers.size();i++){ answer+=to_string(numbers[i]); } return answer; } };
測試程式碼:
// ====================測試程式碼====================
void Test(char* testName, int* numbers, int length, char* expectedResult)
{
if(testName != NULL)
printf("%s begins:\n", testName);
if(expectedResult != NULL)
printf("Expected result is: \t%s\n", expectedResult);
printf("Actual result is: \t");
PrintMinNumber(numbers, length);
printf("\n");
}
void Test1()
{
int numbers[] = {3, 5, 1, 4, 2};
Test("Test1", numbers, sizeof(numbers)/sizeof(int), "12345");
}
void Test2()
{
int numbers[] = {3, 32, 321};
Test("Test2", numbers, sizeof(numbers)/sizeof(int), "321323");
}
void Test3()
{
int numbers[] = {3, 323, 32123};
Test("Test3", numbers, sizeof(numbers)/sizeof(int), "321233233");
}
void Test4()
{
int numbers[] = {1, 11, 111};
Test("Test4", numbers, sizeof(numbers)/sizeof(int), "111111");
}
// 陣列中只有一個數字
void Test5()
{
int numbers[] = {321};
Test("Test5", numbers, sizeof(numbers)/sizeof(int), "321");
}
void Test6()
{
Test("Test6", NULL, 0, "Don't print anything.");
}
int _tmain(int argc, _TCHAR* argv[])
{
Test1();
Test2();
Test3();
Test4();
Test5();
Test6();
return 0;
}
#Coding一小時,Copying一秒鐘。留個言點個讚唄,謝謝你#