Leetcode剑指offer面试题45.把数组排成最小的数

      初看这道题总结出的规律是识别出每一个数字的每一位数,然后对每一个数从第一位开始比较,若第一位相同,则开始比较第二位的数字,直到找到某一个数的某一位达到最小且没有其余的数和它一样。最终我自己的想法是,每次先设第一个数字为最小值,然后从第二个数字开始与他进行比较,按照每一位比较的规律来进行排序,最后按照选择排序的思路,每次都选一个最小的放在最前面,来进行排序。最终代码如下:

public static String minNumber(int[] nums) {
    for (int i = 0; i < nums.length; i++){
        for (int j = i + 1; j < nums.length; j++){
            //此时说明nums[i] > nums[j]
            if (compare(nums[i], nums[j]) > 0){
                int temp = nums[i];
                nums[i] = nums[j];
                nums[j] = temp;
            }
        }
    }
    StringBuilder res = new StringBuilder();
    for(int s : nums)
        res.append(s);
    return res.toString();
}
public static int compare(int a, int b){
    Deque<Integer> a_digit = new ArrayDeque<>();
    Deque<Integer> b_digit = new ArrayDeque<>();
    while (a > 0){
        a_digit.addFirst(a % 10);
        a /= 10;
    }
    while (b > 0){
        b_digit.addFirst(b % 10);
        b /= 10;
    }
    //得到a或者b的第一位,方便当a与b长度不等的时候,作为比较的依据
    int a_first = a_digit.peekFirst();
    int b_first = b_digit.peekFirst();
    while(!a_digit.isEmpty() && !b_digit.isEmpty()){
        if (a_digit.peekFirst() > b_digit.peekFirst()){
            return 1;
        }
        else if (a_digit.peekFirst() < b_digit.peekFirst()){
            return -1;
        }
        a_digit.pollFirst();
        b_digit.pollFirst();
    }
    return 0;
}

但是但是!这段代码是有问题的,因为没有考虑到3和34的情况,好嘛这个简单,我再最后加几个if判断,存下来这两个数字的第一位就好了,然后一个数里面多余的数字和另一个数的第一位进行比较就好啦,因为34里面的4>另一个数字3,所以3应该放在34的前面嘛,3“<”34。但很遗憾的是这样的判断无法比较12和121.

所以感觉这样的思路是不行的,按照逐位比较的方法很难去判断两个数的排序。经过一番挣扎后,终于决定点开题解!

果然。。。大佬们就是不一样,别人的排序思路是这样的:如果x y > y x,则x > y,x要放在y的后面。若x y < y x,则x < y,y要放在x的后面。然后选择排序也是时间负责度很高的排序,可以替换为快排。然后利用String类里面的compareTo方法,可以更加快捷地将两个数字拼接在一起,并比较两种不同拼接顺序的大小。

这里说一下compareTo方法:

compareTo方法是按照字典顺序比较两个字符串。如果按照字典顺序比较,调用方法的String 对象在参数字符串之前,则比较结果为一个负数。如果按字典顺序调用方法的String 对象位于参数字符串之后,则比较结果为一个正整数。如果这两个字符串相等,则结果为 0。

最终根据提示,代码变成了这样:

public String minNumber(int[] nums) {
        String[] strs = new String[nums.length];
        for(int i = 0; i < nums.length; i++)
            strs[i] = String.valueOf(nums[i]);
        kuaipai(strs, 0, strs.length - 1);
        StringBuilder res = new StringBuilder();
        for(String s : strs)
            res.append(s);
        return res.toString();
    }

public void kuaipai(String[] nums, int left, int right){
   if (left <= right){
       String base = nums[left];
       int i = left, j = right;
       while (i < j) {
           while ((nums[j] + base).compareTo(base + nums[j]) >= 0 && j > i) {
               j--;
           }
           while ((nums[i] + base).compareTo(base + nums[i]) <= 0 && i < j) {
               i++;
           }
           String temp = nums[j];
           nums[j] = nums[i];
           nums[i] = temp;
       }
       nums[left] = nums[i];
       nums[i] = base;
      kuaipai(nums, left, i - 1);
      kuaipai(nums, i + 1, right);
   }
}

你以为这样就结束?当然是不行的,再看看有没有其它的解法。果然还是有的,而且更加精简。上文也说到了这道题的核心思路就是更改一下排序的规则,那当然是利用系统的排序方法让代码更加精简,此时就可以重构Java里的compare方法。注意Arrays.sort(num(数组名), start, end, new cmp())。是起始位置和结束位置默认为整个数组,然后比较函数cmp也会默认按照升序排列。默认的cmopare函数即int compare(Object o1, Object o2)。如果o1小于o2,返回-1。相等返回0,o1大于o2则返回1。

public class mycmp implements Comparator<String>{
    @Override
    public int compare(String o1, String o2) {
        return (o1+o2).compareTo(o2 + o1);
    }
}
public String minNumber1(int[] nums) {
    String[] strs = new String[nums.length];
    for(int i = 0; i < nums.length; i++)
        strs[i] = String.valueOf(nums[i]);
    Arrays.sort(strs, new mycmp());
    StringBuilder res = new StringBuilder();
    for(String s : strs)
        res.append(s);
    return res.toString();
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值