leetcode-179-Largest Number(理解規則,自定義cmp函數進行排序)

題目描述:

給定一組非負整數,重新排列它們的順序使之組成一個最大的整數。

示例 1:

輸入: [10,2]
輸出: 210

示例 2:

輸入: [3,30,34,5,9]
輸出: 9534330

說明: 輸出結果可能非常大,所以你需要返回一個字符串而不是整數。

要完成的函數:

string largestNumber(vector<int>& nums) 

說明:

1、這道題給定一個vector,裏面存放着int類型的非負整數,要求把這些非負整數拼起來,儘可能拼成一個最大的整數。

比如[10,2],可以拼成102,也可以拼成210,最大的整數就是210,那麼返回210,以字符串的形式。

2、這道題關鍵在於判斷,判斷vector中的兩個數誰大誰小,誰應該放在前面。

舉個例子,比如[3,30,31,32,33,34,35,102,9,990],大家覺得應該怎麼排序?

我們要儘可能讓大的數字放在前面,所以首位肯定要放個大一點的,那麼就是9了,其餘的都是3,放在首位不合適。

那麼9有兩個,要放9還是990,這裏要對這兩個數的組合做個判斷。

一種是9990,一種是9909,所以還是9-990這種組合。

那麼接下來呢,9-990之後呢?3跟30比,一種是330,一種是303,所以還是3在30前面。

那3跟31比呢,一種是331,一種是313,還是3在31前面。

是不是所有短的數字都要放在前面?

其實不是的,比如3和34,一種是334,一種是343,還要考慮到後面這一位的情況。

所以最終排列下來,“降序”排列,是[9,990,35,34,33,3,32,31,30]。

按照這個vector從前往後添加到要返回的字符串中,就可以了。

這道題的關鍵在於判斷誰在前誰在後,比較的方法也很普通,就是補齊兩個字符串,比較誰大誰小。

當然在實際操作中,沒有必要真的對字符串補齊,我們同樣可以操作。

代碼如下:(附詳解)

    static bool cmp(int &a1,int &b1)//自定義一個比較函數,大的放前面
    {
    	string a=to_string(a1),b=to_string(b1);//先把兩個整數轉化爲字符串,操作起來比較方便
        int s1=a.size(),s2=b.size();
        if(s1<s2)//如果a短b長
        {
            for(int i=0;i<s1;i++)//在a的長度內比較
            {
                if(a[i]>b[i])//如果發現a中的某一位數值已經大於b中同一位的數值,比如4和39
                    return true;//那麼比較到此結束,4要放在前面
                else if(a[i]<b[i])//如果發現a中的某一位數值已經小於b中同一位的數值,比如4和61
                    return false;//那麼比較到此結束,61要放在前面
            }
            for(int i=s1;i<s2;i++)//如果上面的比較沒出結果,比如4和456這種情況,那麼開始新的比較,直到到達第二個字符串的最後一位
            {            //這個循環其實比較的是4和5,5和6,到達第二個字符串的最後一位就不比較了
                if(b[i-s1]>b[i])//如果滿足條件,那麼a要放在前面
                    return true;
                else if(b[i-s1]<b[i])//如果滿足條件,那麼b要放在前面
                    return false;
            }
            for(int i=0;i<s1;i++)//如果上面的比較沒出結果,其實我們還有最後一位沒有比較,6和4
            {
            	if(a[i]<b[s2-s1+i])
            		return true;
            	else if(a[i]>b[s2-s1+i])
            		return false;
			}
            return false;//如果上述比較都沒出結果,比如3和333,那麼返回false,這裏隨便拼都可以
        }
        else if(s1>s2)//如果a長b短,一樣的比較方式
        {
            for(int i=0;i<s2;i++)
            {
                if(a[i]<b[i])
                    return false;
                else if(a[i]>b[i])
                    return true;
            }
            for(int i=s2;i<s1;i++)
            {
                if(a[i-s2]>a[i])
                    return false;
                else if(a[i-s2]<a[i])
                    return true;
            }
            for(int i=0;i<s2;i++)
            {
            	if(b[i]>a[s1-s2+i])
            		return true;
            	else if(b[i]<a[s1-s2+i])
            		return false;
			}
            return false;
        }
        else//如果兩個一樣長,那麼直接逐位比較就可以了
        {
            for(int i=0;i<s1;i++)
            {
                if(a[i]>b[i])
                    return true;
                else if(a[i]<b[i])
                    return false;
            }
            return false;
        }
    }
    string largestNumber(vector<int>& nums) 
    {
        sort(nums.begin(),nums.end(),cmp);//調用sort函數進行排序,排序準則是我們自定義的比較函數
        string res;
        for(auto i:nums)
            res+=to_string(i);//不斷地插入到字符串的末尾
        if(res[0]=='0')return "0";//邊界條件,如果第一位是0,那麼說明後面即使有,也是全0,這時候我們只需要返回0就可以了了,而不是一長串的0
        return res;
    }

上述代碼實測4ms,beats 99.85% of cpp submissions。

關於cmp函數,筆者在網上看到過一個簡單的降序排列的版本,如下:

    bool cmp1(int &a,int &b)
    {
    	return a>b;
	}
    int main()
	{
		vector<int>nums={1,2,3,4,5,6,7,8,9,10,11,12};
		sort(nums.begin(),nums.end(),cmp1);
		for(int i:nums)
		cout<<i<<"  ";
		cout<<endl;
		return 0;
	} 

上面的cmp1這個函數,筆者個人猜想其實是說,如果a>b,那麼返回true,認爲前面的數大於後面的數是正確的。

所以在進行排序的時候,如果前面的數大於後面的,那麼經過cmp1這個函數,返回true,認爲正確,所以不用更改。

如果前面的數小於後面的數,那麼經過cmp1這個函數,返回false,認爲錯誤,所以要換一下位置。

所以筆者就根據自己的猜想,設計了題解代碼中的cmp函數,從結果來看,上述認識還是有一定可取之處的。

但上述僅爲筆者個人的猜想,有可能是不完全的甚至有些錯誤,沒有仔細地去查sort函數的參數,僅作爲一個個人的認識。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章