剑指Offer面试题33把数组排成最小的数,面试题34丑数

面试题33:把数组排成最小的数

输入一个正整数数组,把数组中所有的数拼接起来组成一个数,输出最小的。比如输入{3,32,321},输出321323。
思路1:全排列,类似面试题28,n个数共有n!个排列,复杂度比较高。
思路2:重写一种比较大小的方法,详见代码。
Java实现如下:

import java.util.Arrays;
import java.util.Comparator;

public class PrintMinNumber {
    public static String printMinNumber(int[] numbers) {
        if(numbers == null || numbers.length == 0) return "";

        int len = numbers.length;
        String[] str = new String[len];
        StringBuilder sb = new StringBuilder();
        for(int i = 0; i < len; i++){
            str[i] = String.valueOf(numbers[i]);
        }
        // 重写数组的排序方法。最后返回时用的字符串比较方法,比如111和1101比较,是111大。
        Arrays.sort(str,new Comparator<String>(){
            @Override
            public int compare(String s1, String s2) {
                String c1 = s1 + s2;
                String c2 = s2 + s1;
                return c1.compareTo(c2);
            }
        });
        for(int i = 0; i < len; i++){
            sb.append(str[i]);
        }
        return sb.toString();
    }
    public static void main(String[] args) {
        int[] a = {3,32,321};
        String b = printMinNumber(a);
        System.out.println(b);
    }
}

面试题34:丑数

只包含因子2,3,5的数为丑数,1是第一个丑数,求按从小到大排序的第1500个丑数。例如6和8都是丑数,但14不是,因为它包含因子7。
思路1:所谓一个数m是另一个数n的因子,是指n能被m整除,所以丑数只能被2,3,5整除。如果一个数能被2整除,就把它连续除以2;能被3整除就连续除以3;能被5整除就连续除以5,如果最后得到的是1,那么这个数就是丑数。此方法按顺序判断每一个数即可,效率太低。
思路2:用空间换时间。思路1的弊端在于一个数不管是不是丑数我们都要去算,思路2是一种只计算丑数的方法。因为每一个丑数都是前面的丑数乘以2或3或5得到的,我们把这些丑数放进一个数组中排序即可,具体方法是:
假设数组中已经有若干个排好序的丑数,最大的为M,下一个要放进来的数肯定是前面某一个丑数乘2或3或5的结果,所以我们首先把已有的每个丑数乘以2,得到的结果会有比M小的数,由于前面的数是按顺序的,所以小于M的数肯定已经在数组中了就不用考虑了,我们只需要比M大的第一个数,记为M2,同理得到M3和M5,那么下一个丑数就是三者中的最小的。
注意:前边说把已有的每个丑数都乘以2,3,5,这是不必要的,比如对乘以2来说,肯定会有一个丑数T2,在它之前的每个丑数乘以2后得到的数都会比最大的丑数M小,所以我们只需要记下这个T2就行了,详见代码。
Java实现如下:

public class UglyNumber {
    public int GetUglyNumber(int n){
        if(n < 0){
            return 0;
        }
        int[] uglyNumbers = new int[n];
        uglyNumbers[0] = 1;
        int multiply2 = 1;
        int multiply3 = 1;
        int multiply5 = 1;
        for(int i = 1; i < uglyNumbers.length; i++){
            // 找比M大的第一个数
            int min = Math.min(Math.min(multiply2 * 2, multiply3 * 3), multiply5 * 5);
            uglyNumbers[i] = min;
            // 找T2,T3,T5
            while(multiply2 * 2 <= min){
                multiply2++;
            }
            while(multiply3 * 3 <= min){
                multiply3++;
            }
            while(multiply5 * 5 <= min){
                multiply5++;
            }
        }
        return uglyNumbers[n-1];
    }
    public static void main(String[] args) {
        UglyNumber test = new UglyNumber();
        System.out.println(test.GetUglyNumber(1500));
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值