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