剑指Offe(java版):把数组排成最小的数

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

这个题目最直接的做法应该是先求出这个数组中的所有数字的全排列,然后把每个排列拼接起来,最后求出排列起来的数字的最小值。求数组的排列和面试题28非常相似。根据排列组合的只是,n个数字总共有n!排列,我们再来看一下更快的算法。

这道题其实希望我们能够找到一个排序规则,数组根据这个规则排序之后能排成一个最小的数字。要确定排序的规则,就要比较两个数字,也就是给出两个数字m和n,我们需要确定一个规则判断m和n哪个应该排在前面,而不是仅仅比较这两个数字的值哪个更大。

根据题目的要求,两个数字m和n能拼接称数字mn和nm。如果mn<nm,那么我们应该打印出mn,也就是m应该拍在N的前面,我们定义此时m小于n;反之,如果nm<mn,我们定义n小于m。如果mn=nm,m等于n。

接下来考虑怎么去拼接数字,即给出数字m和n,怎么得到数字mn和nm并比较他们的大小。直接用数值去计算不难办到,但需要考虑一个潜在的问题就是m和n都在int能表达的范围内,把他们拼起来的数字mn和nm用int表示就有可能溢出了,所以这还是一个隐形的大数问题。

一个非常直观的解决大数问题的办法就是把数字转换成字符串。另外,由于把数字m和n拼接起来得到mn和nm,他们的位数肯定是相同的,因此比较它们的大小只需要按照字符串的大小的比较规则就可以了。

基于这个思路,我们实现代码:

 

package cglib;

public class jiekou {

       public void printMin(int[] arr){  
            int[] clone = arr.clone();  
            printMinNumber(clone,0,clone.length-1);  
            for(int i : clone)  
                System.out.print(i);  
        }  
        //核心+快排  
        public void printMinNumber(int[] arr,int left,int right){  
            System.out.println("left="+left);
            System.out.println("right="+right);
            if(left < right){
                System.out.println("arr[right]="+arr[right]);
                
                int main_number = arr[right];//321 ,n
                System.out.println("main_number="+main_number);
                int small_cur = left;  
                System.out.println("small_cur="+small_cur);
                for(int j = left;j<right;j++){
                    System.out.println("j="+j);
                    System.out.println("arr[j]="+arr[j]);//3,m
                    if(isSmall(String.valueOf(arr[j]),String.valueOf(main_number))){  
                        System.out.println("arr[j]小于main_number,交换arr[j]和arr[small_cur]");
                        int temp = arr[j];  
                        arr[j] = arr[small_cur];  
                        arr[small_cur] = temp;
                        System.out.println("small_cur="+small_cur);
                        small_cur++;
                        System.out.println("small_cur="+small_cur);
                    }  
                }  
                System.out.println("arr[right]="+arr[right]);
                System.out.println("arr[small_cur]="+arr[small_cur]);
                System.out.println("main_number="+main_number);
                arr[right]= arr[small_cur];
                System.out.println("交换后arr[right]="+arr[right]);
                arr[small_cur] = main_number;
                System.out.println("交换后arr[small_cur]="+arr[small_cur]);
                System.out.println("small_cur="+small_cur);
                printMinNumber(arr,0,small_cur-1);  
                printMinNumber(arr,small_cur+1,right);  
            }  
        }  
        public boolean isSmall(String m,String n){
            System.out.println("进入isSmall");
            System.out.println("m="+m);
            System.out.println("n="+n);
            String left = m+n;  
            String right = n+m;
            System.out.println("left="+left);
            System.out.println("right="+right);
            System.out.println("left.length()="+left.length());
            boolean result = false;  
            for(int i = 0;i<left.length();i++){
                System.out.println("比较m和n组成的数的每个子数的大小,如果mn<nm,则返回真");
                System.out.println("i="+i);
                System.out.println("left.charAt(i)="+left.charAt(i));
                System.out.println("right.charAt(i)="+right.charAt(i));
                if(left.charAt(i)<right.charAt(i))  
                    return true;  
                else  
                    if(left.charAt(i)>right.charAt(i))  
                        return false;  
            }  
            return result;  
        }  
        public static void main(String[] args){  
            int arr[] = {3,32,321};  
            jiekou test = new jiekou();  
            test.printMin(arr);  
        }  
    }   

 


输出:

left=0
right=2
arr[right]=321
main_number=321
small_cur=0
j=0
arr[j]=3
进入isSmall
m=3
n=321
left=3321
right=3213
left.length()=4
比较m和n组成的数的每个子数的大小,如果mn<nm,则返回真
i=0
left.charAt(i)=3
right.charAt(i)=3
比较m和n组成的数的每个子数的大小,如果mn<nm,则返回真
i=1
left.charAt(i)=3
right.charAt(i)=2
j=1
arr[j]=32
进入isSmall
m=32
n=321
left=32321
right=32132
left.length()=5
比较m和n组成的数的每个子数的大小,如果mn<nm,则返回真
i=0
left.charAt(i)=3
right.charAt(i)=3
比较m和n组成的数的每个子数的大小,如果mn<nm,则返回真
i=1
left.charAt(i)=2
right.charAt(i)=2
比较m和n组成的数的每个子数的大小,如果mn<nm,则返回真
i=2
left.charAt(i)=3
right.charAt(i)=1
arr[right]=321
arr[small_cur]=3
main_number=321
交换后arr[right]=3
交换后arr[small_cur]=321
small_cur=0
left=0
right=-1
left=1
right=2
arr[right]=3
main_number=3
small_cur=1
j=1
arr[j]=32
进入isSmall
m=32
n=3
left=323
right=332
left.length()=3
比较m和n组成的数的每个子数的大小,如果mn<nm,则返回真
i=0
left.charAt(i)=3
right.charAt(i)=3
比较m和n组成的数的每个子数的大小,如果mn<nm,则返回真
i=1
left.charAt(i)=2
right.charAt(i)=3
arr[j]小于main_number,交换arr[j]和arr[small_cur]
small_cur=1
small_cur=2
arr[right]=3
arr[small_cur]=3
main_number=3
交换后arr[right]=3
交换后arr[small_cur]=3
small_cur=2
left=0
right=1
arr[right]=32
main_number=32
small_cur=0
j=0
arr[j]=321
进入isSmall
m=321
n=32
left=32132
right=32321
left.length()=5
比较m和n组成的数的每个子数的大小,如果mn<nm,则返回真
i=0
left.charAt(i)=3
right.charAt(i)=3
比较m和n组成的数的每个子数的大小,如果mn<nm,则返回真
i=1
left.charAt(i)=2
right.charAt(i)=2
比较m和n组成的数的每个子数的大小,如果mn<nm,则返回真
i=2
left.charAt(i)=1
right.charAt(i)=3
arr[j]小于main_number,交换arr[j]和arr[small_cur]
small_cur=0
small_cur=1
arr[right]=32
arr[small_cur]=32
main_number=32
交换后arr[right]=32
交换后arr[small_cur]=32
small_cur=1
left=0
right=0
left=2
right=1
left=3
right=2
321323

或者:

package cglib;

import java.util.Arrays;

public class jiekou {

      public static void main(String ss[]) {  
          
            MString s[] = new MString[3];  
            s[0] = new MString();  
            s[0].src = "3";  
            s[1] = new MString();  
            s[1].src = "32";  
            s[2] = new MString();  
            s[2].src = "321";  
            function(s);  
            for (int i = 0; i < s.length; i++) {  
                System.out.print(s[i].src);  
            }  
      
        }  
      
        public static void function(MString s[]) {  
            Arrays.sort(s);  
        }  
    }  
      
    class MString implements Comparable<MString> {  
      
        @Override  
        public String toString() {  
            return "MString [src=" + src + "]";  
        }  
      
        String src;  
      
        @Override  
        public int compareTo(MString paramT) {
            System.out.println("this.src="+this.src);
            System.out.println("paramT.src="+paramT.src);
            String s1 = this.src + paramT.src;  
            System.out.println("s1="+s1);
            String s2 = paramT.src + this.src;  
            System.out.println("s2="+s2);
            if (s1.compareTo(s2) == 0) {  
                return 0;  
            } else if (s1.compareTo(s2) > 0) {  
                return 1;  
            } else  
                return -1;  
        }
    }

MString用来存储要比较的字符串,实现了compare函数,用来比较。

compare函数的意思是如果组成的数字mn>nm,那么就返回nm,否则返回mn。

---------------------------------

下面说一下Comparable接口。

实现该接口的话,需要实现comparaTo函数。这个函数是用于两个对象做比较的。如果相等则返回0,大则返回1,小则返回-1。

在上面的代码中,我们实现了Comparable接口并且在实现的函数中做了两个字符串的比较。

实现了Comparable接口的所有类都可以使用comparaTo函数来比较大小。

 

输出:
this.src=32
paramT.src=3
s1=323
s2=332
this.src=321
paramT.src=32
s1=32132
s2=32321
321323

或者

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

public class jiekou {

      public static void main(String ss[]) {  
          
            //int s[] = new int[3];
          int s[] = {3,32,321};  
          jiekou test = new jiekou();  
            
            System.out.print(test.PrintMinNumber(s));  
              
      
        }  
      
      public String PrintMinNumber(int [] numbers) {
            String[] s = new String[numbers.length];
            for (int i = 0; i < s.length; i++)
                s[i] = String.valueOf(numbers[i]);
            Arrays.sort(s, 0, s.length, new Comparator<String>() {
    
                @Override
                public int compare(String o1, String o2) {
                    return (o1+o2).compareTo(o2+o1);
                }
            });
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < s.length; i++)
                sb.append(s[i]);
             
            return sb.toString();
        }
    }   

 

转载于:https://my.oschina.net/u/2822116/blog/725014

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值