1. 程式人生 > >#資料結構與演算法學習筆記#劍指Offer30:把陣列排成最小的數 + 自定義比較器 + 測試用例(Java、C/C++)

#資料結構與演算法學習筆記#劍指Offer30:把陣列排成最小的數 + 自定義比較器 + 測試用例(Java、C/C++)

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一秒鐘。留個言點個讚唄,謝謝你#