目录
力扣题址:
今天刷破解闯关密码(把数组排成最小的数),大家有兴趣可以点上看看题目要求,试着做一下。
难度:中等
但不了解快速排序方法的话有点挺难的。
我们直接看题解吧:
方法是快速排序方法
审题目+事例+提示:
·返回字符串即可(可能出现数字过大)
·不必去掉前到0,若有的话
解题思路(快排):
判定规则:
设数组的;两个数字的字符串为x,y
若x+y>y+x,则x‘大于’y
反之x+y<y+x,则x’小于’y
’小于‘即排序后,x应在y的左边,‘大于’反之
注意,这里是字符串的拼接,以及 <,>是字符串的比较
而‘大于’、‘小于’是我们自己定义的规则。
至于规则比较合理性证明如下:(涉及离散数学知识)
字符串 xy < yx , yz < zy ,需证明 xz < zx 一定成立。 设十进制数 x, y, z 分别有 a, b, c 位,则有: (左边是字符串拼接,右边是十进制数计算,两者等价) xy = x * 10^b + y yx = y * 10^a + x 则 xy < yx 可转化为: x * 10^b + y < y * 10^a + x x (10^b - 1) < y (10^a - 1) x / (10^a - 1) < y / (10^b - 1) ① 同理, 可将 yz < zy 转化为: y / (10^b - 1) < z / (10^c - 1) ② 将 ① ② 合并,整理得: x / (10^a - 1) < y / (10^b - 1) < z / (10^c - 1) x / (10^a - 1) < z / (10^c - 1) x (10^c - 1) < z (10^a - 1) x * 10^c + z < z * 10^a + x ∴ 可推出 xz < zx ,传递性证毕
反证法:
根据算法,如果a < b,那么a排在b前面,否则b排在a前面。可利用反证法,假设排成的最小数字为xxxxxx,并且至少存在一对字符串满足这个关系:a > b,但是在组成的数字中a排在b前面。根据a和b出现的位置,分三种情况考虑:
(1)xxxxab,用ba代替ab可以得到xxxxba,这个数字是小于xxxxab,与假设矛盾。因此排成的最小数字中,不存在上述假设的关系。 (2)abxxxx,用ba代替ab可以得到baxxxx,这个数字是小于abxxxx,与假设矛盾。因此排成的最小数字中,不存在上述假设的关系。 (3)axxxxb,这一步证明麻烦了一点。可以将中间部分看成一个整体ayb,则有ay < ya,yb < by成立。将ay和by表示成10进制数字形式,则有下述关系式,这里a,y,b的位数分别为n,m,k。 关系1: ay < ya => a * 10^m + y < y * 10^n + a => a * 10^m - a < y * 10^n - y => a( 10^m - 1)/( 10^n - 1) < y 关系2: yb < by => y * 10^k + b < b * 10^m + y => y * 10^k - y < b * 10^m - b => y < b( 10^m -1)/( 10^k -1) 关系3: a( 10^m - 1)/( 10^n - 1) < y < b( 10^m -1)/( 10^k -1) => a/( 10^n - 1)< b/( 10^k -1) => a*10^k - a < b * 10^n - b =>a*10^k + b < b * 10^n + a => a < b 这与假设a > b矛盾。因此排成的最小数字中,不存在上述假设的关系。 综上所述,得出假设不成立,从而得出结论:对于排成的最小数字,不存在满足下述关系的一对字符串:a > b,但是在组成的数字中a出现在b的前面。从而得出算法是正确的
具体如下图所示:
具体思路:
- 创建一个字符串strs,并使用循环,把整数数组转为字符串
- 将字符串传到我们要创建的quickSort()函数中去
- 在quickSort()函数中传入字符串,以及0即l与字符串尾元素,r
- 创建临时字符串tmp,i=l,j=r
- 进行循环i<j:
若j+l>l+j,则j--
若i+l<l+i,则i++
然后i与j交换对应元素
6、l与i交换对应元素
7、再进行两次调用quickSort函数,传入(strs,l,i-1),和(strs,i-1,r)
8、最后对字符串进行拼接
9、返回字符串
代码:
class Solution {
public String crackPassword(int[] password) {
String[] strs = new String[password.length];
for(int i = 0; i < password.length; i++)
//这里用到valueOf()方法将整数数组转为字符串数组
strs[i] = String.valueOf(password[i]);
quickSort(strs, 0, strs.length - 1);
StringBuilder res = new StringBuilder();
for(String s : strs)
res.append(s);
return res.toString();
}
void quickSort(String[] strs, int l, int r) {
if(l >= r) return;//数组为空,直接return结束,否则会出现栈溢出
int i = l, j = r;
String tmp = strs[i];
while(i < j) {
while((strs[j] + strs[l]).compareTo(strs[l] + strs[j]) >= 0 && i < j) j--;
while((strs[i] + strs[l]).compareTo(strs[l] + strs[i]) <= 0 && i < j) i++;
tmp = strs[i];
strs[i] = strs[j];
strs[j] = tmp;
}
strs[i] = strs[l];
strs[l] = tmp;
quickSort(strs, l, i - 1);
quickSort(strs, i + 1, r);
}
}
注:虽然比较规则部分即qickSort()函数比较繁杂,但建议先看看这个,理解一下思路,然后在试试下面的。
代码(利用内置函数):
class Solution {
public String crackPassword(int[] password) {
String[] strs = new String[password.length];
for(int i = 0; i < password.length; i++)
strs[i] = String.valueOf(password[i]);
Arrays.sort(strs, (x, y) -> (x + y).compareTo(y + x));
StringBuilder res = new StringBuilder();
for(String s : strs)
res.append(s);
return res.toString();
}
}
注:这里用了lamda 表达式,以及Array.sort()排序数组
上一题: