剑指offer-把数组排成最小的数

题目描述

输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323。

思路与实现

way1

https://blog.csdn.net/weixin_44135282/article/details/98781113 与该题字符串的排列类似
求出全排列 拼接起来 求出拼接后的最大值 n个数字n!个排列

import java.util.*;

public class Solution {
    public static String PrintMinNumber(int[] numbers) {
        List<List<Integer>> res = new ArrayList<List<Integer>>();
        if (numbers == null || numbers.length == 0)
            return "";
        boolean[] used = new boolean[numbers.length];
        List<Integer> list = new ArrayList<Integer>();
        Arrays.sort(numbers);//排序
        dfs(numbers, used, list, res);
        String[] results = new String[res.size()];
        int i = 0;
        for (List<Integer> one : res) {
            String sf = "";
            for (Integer num : one)
                sf += Integer.toString(num.intValue());
            results[i] = sf;
            i++;
        }
        String min = results[0];
        for (int j = 0; j < results.length; j++) {
            if (results[j].compareTo(min) < 0)
                min = results[j];
        }
        return min;

    }

    public static void dfs(int[] nums, boolean[] used, List<Integer> list, List<List<Integer>> res) {
        if (list.size() == nums.length) {
            res.add(new ArrayList<Integer>(list));
            return;
        }
        for (int i = 0; i < nums.length; i++) {
            if (used[i])
                continue;
            //只需要判断i和i-1(而不需要判断i与i-2...) 相同的元素一定是相邻的。
            //如果i-2,i-1,i相同,那么在上一轮循环就已经判断了i-1,i,本轮循环不需要重复判断
            //重复元素只按顺序选择,若当前元素未被选择且前一元素与当前元素值相等也未被选择则跳过,这一可能情况与先选小序号后选大序号的相同元素相同
            if (i > 0 && nums[i - 1] == nums[i] && !used[i - 1]) continue;
            used[i] = true; //标记用过
            list.add(nums[i]);
            dfs(nums, used, list, res);
            used[i] = false;//标记清除
            list.remove(list.size() - 1); //退回一个
        }
    }
}

way2

https://www.nowcoder.com/profile/2913706/codeBookDetail?submissionId=28841735以及剑指offer书籍上
找到一个排序规则,数组根据这个排序规则之后能排成一个最小的数字
排序规则就是比较两个数字 给出数字m和n 需要确定一个规则判断m和n哪个应该排在前面(mn还是nm)

  • mn
  • nm
  • nm=mn 定义m=n
    直接比较数值的大小可能超过整数所表达的范围造成溢出,所以把数字转为字符串,nm与mn位数相同,直接用字符串比较大小的规则
import java.util.Arrays;
import java.util.Comparator;
public class Solution {
    public String PrintMinNumber(int[] numbers) {
        if (numbers == null || numbers.length == 0)
            return "";
        int length = numbers.length;
        String[] str = new String[length];
        for (int i = 0; i < length; i++) {
            str[i] = String.valueOf(numbers[i]); //int转String
        }
        Arrays.sort(str, new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
            	return (o1+o2).compareTo(o2+o1);// o1o2
            }
        });

        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < length; i++) {
            sb.append(str[i]);
        }
        return sb.toString();
    }
}

比如输入数组{3,32,321}
o1=3,o2=32 o1o2>o2o1 o2排在前面 结果为 32,3
o1=32,o2=321 o1o2>o2o1 o2排在前面 结果为 321,32
所以结果为321,32,3,合并为321323

所用知识点

java字符串比较大小

Str1.compareTo(Str2);
其返回的是一个int类型值。

java字符串比较规则

(http://www.blogjava.net/hgc-ghc/archive/2013/03/28/397084.html)
String a=“a”,b=“b”;
System.out.println(a.compareto.b);
则输出-1;
若a=“a”,b="a"则输出0;
若a=“b”,b="a"则输出1;

单个字符这样比较,若字符串比较长呢??
若a=“ab”,b=“b”,则输出-1;
若a=“abcdef”,b="b"则输出-1;
也就是说,如果两个字符串首字母不同,则该方法返回首字母的asc码的差值;

如果首字母相同呢??
若a=“ab”,b=“a”,输出1;
若a=“abcdef”,b="a"输出5;
若a=“abcdef”,b="abc"输出3;
若a=“abcdef”,b="ace"输出-1;
即参与比较的两个字符串如果首字符相同,则比较下一个字符,直到有不同的为止,返回该不同的字符的asc码差值,
如果两个字符串不一样长,可以参与比较的字符又完全一样,则返回两个字符串的长度差值

你可能感兴趣的:(剑指offer)