解闯关密码(把数组排成最小的数),剑指offer,力扣

目录

我们直接看题解吧:

审题目+事例+提示:

解题思路(快排):

判定规则:

具体思路:

代码:

代码(利用内置函数): 


力扣题址:

LCR 164. 破解闯关密码 - 力扣(LeetCode)

今天刷破解闯关密码(把数组排成最小的数),大家有兴趣可以点上看看题目要求,试着做一下

难度:中等

但不了解快速排序方法的话有点挺难的。

我们直接看题解吧:

方法是快速排序方法

审题目+事例+提示:

·返回字符串即可(可能出现数字过大)

·不必去掉前到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的前面。从而得出算法是正确的 

具体如下图所示:

解闯关密码(把数组排成最小的数),剑指offer,力扣_第1张图片

具体思路:

  1. 创建一个字符串strs,并使用循环,把整数数组转为字符串
  2. 将字符串传到我们要创建的quickSort()函数中去
  3. 在quickSort()函数中传入字符串,以及0即l与字符串尾元素,r
  4. 创建临时字符串tmp,i=l,j=r
  5. 进行循环i

          若j+l>l+j,则j--

          若i+l

            然后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()排序数组


 上一题:

连续天数的最高销售额(连续子数组的最大和),剑指offer,力扣-CSDN博客

你可能感兴趣的:(#,数组,剑指offer,算法,数据结构)