leetcode179_最大数
1. 题意
给一个数组,你可以任意改变顺序来拼接组成一个大数;
问能组成的最大的数是多少。
答案是比较两个数前后拼接后的大小;我反正是觉得这种想法一点都不
自然。
还是抄下数学证明吧。
2. 证明
我们定义两个正数字符串的拼接操作符号为 ⊕ \oplus ⊕
a ⊕ b = a S ( b ) + b a \oplus b =aS(b)+b a⊕b=aS(b)+b
其中函数 S ( x ) S(x) S(x)表示,超过 x x x的最小整十进制数
S ( x ) = 10 ⌊ lg x ⌋ + 1 S(x)=10^{\lfloor \lg x\rfloor+1} S(x)=10⌊lgx⌋+1
特别地
S ( 0 ) = 10 S(0) =10 S(0)=10
显然拼接操作是符合结合律的,当然证明没那么显然。
我们定义二元关系两个正整数 a b a\ b a b的二元关系 @ @ @
a @ b : a ⊕ b ≥ b ⊕ a a@b: a\oplus b \ge b\oplus a a@b:a⊕b≥b⊕a
显然 a b a \ b a b之间的关系要么是 a @ b a@b a@b,要么是 b @ a b@a b@a。
我们来证明 @ @ @关系的传递性,也就是
a @ b ∩ b @ c ⇒ a @ c a@b\ \cap \ b@c \Rightarrow a@c a@b ∩ b@c⇒a@c
代入定义
a @ b ⇔ a S ( b ) + b ≥ b S ( a ) + a b @ c ⇔ b S ( c ) + c ≥ c S ( b ) + b a@b \Leftrightarrow aS(b)+b \ge bS(a)+a\\ b@c \Leftrightarrow bS(c)+c \ge cS(b)+b a@b⇔aS(b)+b≥bS(a)+ab@c⇔bS(c)+c≥cS(b)+b
整理变形
a ( S ( b ) − 1 ) ≥ b ( S ( a ) − 1 ) b ( S ( c ) − 1 ) ≥ c ( S ( b ) − 1 ) a(S(b)-1) \ge b(S(a)-1) \\ b(S(c)-1) \ge c(S(b)-1) a(S(b)−1)≥b(S(a)−1)b(S(c)−1)≥c(S(b)−1)
两个不等式组左边乘左边,右边乘右边得到
a b ( S ( b ) − 1 ) ( S ( c ) − 1 ) ≥ b c ( S ( b ) − 1 ) ( S ( a ) − 1 ) ab(S(b)-1)(S(c)-1) \ge bc(S(b)-1)(S(a)-1) ab(S(b)−1)(S(c)−1)≥bc(S(b)−1)(S(a)−1)
我们发现有相同的项 b ( S ( b ) − 1 ) b(S(b)-1) b(S(b)−1), 还需要讨论 b b b是否为 0 0 0
当 b = 0 b=0 b=0时
b S ( c ) + c = c ≥ c S ( b ) + b = 10 c ⇔ c ≥ 10 c c = 0 a S ( c ) + c ≥ c S ( a ) + a ⇔ 10 a ≥ a \\ bS(c)+c =c \ge c S(b)+b =10c \Leftrightarrow c \ge 10c\\ c=0\\ aS(c)+c \ge cS(a)+a \Leftrightarrow 10a \ge a\\ bS(c)+c=c≥cS(b)+b=10c⇔c≥10cc=0aS(c)+c≥cS(a)+a⇔10a≥a
a @ c a@c a@c成立。
当 b ≠ 0 b \ne 0 b=0时,通过上面的不等式可以直接约去 b ( S ( b ) − 1 ) b(S(b)-1) b(S(b)−1)得到
a ( S ( c ) − 1 ) ≥ c ( S ( a ) − 1 ) ⇔ a S ( c ) + c ≥ c S ( a ) + a a(S(c)-1) \ge c(S(a) -1) \Leftrightarrow\\ aS(c)+c \ge cS(a)+a a(S(c)−1)≥c(S(a)−1)⇔aS(c)+c≥cS(a)+a
a @ c a@c a@c也成立。
综上 @ @ @关系的传递性也成立。
最后我们证明该排序规则的充分性:假设存在一个最优序列不满足该
排序规则,那么必然存在至少一对相邻数字 a 与 b,我们将 a 与 b 交
换后新序列的值必然增加,与假设矛盾。因此,满足该排序规则是该
序列最优的充分条件。
3. 拼接操作的结合律证明
a ⊕ b ⊕ c = a ⊕ ( b ⊕ c ) a \oplus b \oplus c =a\oplus (b \oplus c) a⊕b⊕c=a⊕(b⊕c)
左边代入计算得到
a S ( b ) S ( c ) + b S ( c ) + c aS(b)S(c) + bS(c)+c aS(b)S(c)+bS(c)+c
右边代入计算得到
a S ( b S ( c ) + c ) + b S ( c ) + c aS(bS(c)+c) +bS(c)+c aS(bS(c)+c)+bS(c)+c
只需要证明
a S ( b ) S ( c ) = a S ( b S ( c ) + c ) aS(b)S(c)=aS(bS(c)+c) aS(b)S(c)=aS(bS(c)+c)
即可
我们容易根据定义得到 S ( x ) S(x) S(x)如下性质
S ( x ) = S ( 10 ⌊ lg x ⌋ ) = 10 ⌊ lg x ⌋ + 1 S(x)=S(10^{\lfloor \lg x\rfloor})=10^{\lfloor \lg x\rfloor+1} S(x)=S(10⌊lgx⌋)=10⌊lgx⌋+1
因此我们只需要在意 x x x最高位数即可。
因此
S ( b S ( c ) + c ) = S ( b S ( c ) ) S(bS(c)+c)=S(bS(c)) S(bS(c)+c)=S(bS(c))
我们令 t 1 = ⌊ b ⌋ , t 2 = ⌊ c ⌋ t_1=\lfloor b\rfloor,t_2=\lfloor c\rfloor t1=⌊b⌋,t2=⌊c⌋
因此
S ( b ) S ( c ) = 10 t 1 + 1 10 t 2 + 1 = 10 t 1 + t 2 + 2 S(b)S(c)=10^{t_1+1} 10^{t_2+1} =10^{t_1+t_2+2} S(b)S(c)=10t1+110t2+1=10t1+t2+2
另一方面
S ( b S ( c ) ) = S ( 10 t 2 + 1 b ) = S ( 10 t 1 + t 2 + 1 ) = 10 t 1 + t 2 + 2 S(bS(c))=S(10^{t_2+1}b)=S(10^{t_1+t_2+1})=10^{t_1+t_2+2} S(bS(c))=S(10t2+1b)=S(10t1+t2+1)=10t1+t2+2
因此
S ( b S ( c ) + c ) = S ( b ) S ( c ) S(bS(c)+c)=S(b)S(c) S(bS(c)+c)=S(b)S(c)
综上
a ⊕ b ⊕ c = a ⊕ ( b ⊕ c ) a \oplus b \oplus c =a\oplus (b \oplus c) a⊕b⊕c=a⊕(b⊕c)
成立。
4. 代码
比起证明,代码变得索然无味了。
class Solution {
public:string largestNumber(vector<int>& nums) {sort(nums.begin(), nums.end(), [](int a, int b){std::string as = std::to_string( a );std::string bs = std::to_string( b );return as + bs > bs + as;});if ( nums[0] == 0)return std::string("0");std::string ans;for (int v : nums) {ans.append( std::to_string( v ));}return ans;}
};
参考
lc179
三叶姐的证明思路不错,但感觉局限在定长了,
提供另一个思考角度吧;还是官方的更加严谨一些。