• 天平称球如何代码实现


    久伴说来太遥远,看着背影渐远,不如怀念。

    问题描述:现在有n(n>=2)个球,n个球外观一模一样,但是重量有区别,其中有且仅有一个球的重量比其它n-1个球要重,现在有一个天平,天平是完好无损的,问最少需要称多少次才能确定哪个球的重量较重?

    灵感来源:http://www.cnblogs.com/dolphin0520/archive/2012/10/02/2707762.html(博客园:海子)

    这个问题以前在面试的时候经常遇到,不过记得当时好像没有要求写代码,好像需要推导公式...

    一般在遇到在这个问题的时候,思维会很固定的想到去将n个球平分,每次平分下去称量比较。前两天偶尔又碰见这个问题,博主的思路是将n个球分成2组或者3组来解决。

    个人按照思路归纳了一遍,如果想要写代码实现统一的实现,肯定要有一个固定的模板。于是我的做法就是n>=2的时候,都是分成3组来解决:

    声明:试验证明,平分成2组比较次数远多于3组。

    推导思路:(主要这么推导写代码方便)将n个球分成3组。

    n=2  :     (1,1,0)            最少比较1次                                 

    n=3 :      (1,1,1)            最少比较1次                                  

    n=4:       (2,1,1)            最少比较1次    最多比较2次                               

    n=5:       (2,2,1)            最少比较1次    最多比较2次                                 

    n=6:       (2,2,2)            最少比较2次    最多比较2次                                 

    n=7:       (3,2,2)            最少比较2次    最多比较2次

    n=8:       (3,3,2)            最少比较2次    最多比较2次

    n=9:      (3,3,3)             最少比较2次    最多比较2次

    n=10:    (4,3,3)             最少比较2次    最多比较3次

    n=11:    (4,4,3)             最少比较2次     最多比较3次

    规律:设3组的球个数分别是:(i,j,k)

    那么:如果 n%3=0   则  i=n/3  否则  i=n/3+1

             剩下 n=n-i;

    对于j:如果 n%2=0  则  j=n/2  否则 j=n/2+1

    对于k: k=n-i-j

    如此下来,在n>=2的时候,将n个球分成3组,每组的个数由以上规则确定出来!

    可以看出来,在这么分组后,每组的数据组成大概都会有规律:

    当n%3=0,   分组为(n/3,n/3,n/3)

    当n%3!=0,  分组为(x,x,y)或者(x,y,y)

    按照分为3组的思路,最少次数应该为  3<=n  即 x=n1/3 取整

    java代码:(递归)

    从键盘录入一个数字,按回车即可显示出分组情况以及最后的结果,建议n>3,因为代码没有添加太多数字不合格方面的校验。

    import java.util.Scanner;
    /**
     * there are many balls .find the weighter ball
     * get the time that find the weighter ball(max time)
     * */
    public class WeightestBall {
     
          /**
           * assign group 将n个数分成m组
           * */
          private static void assignGroup(int[] array,int n,int m){
                if(n<2)
                 return;
                if(m==3){
                 if(n%3==0){
                  array[0]=array[1]=array[2]=n/3;
                 }else{
                  array[0]=n/3+1;
                  /*剩余的2组继续通过回调赋值*/
                  assignGroup(array,n-(n/3+1),2);
                 }
                }
                if(m==2){
                 if(n%2==0){
                  array[1]=array[2]=n/2;
                 }else{
                  array[1]=n/2+1;
                  array[2]=n-array[1]-array[2];
                 }
                }
                System.out.println("
    assgin group result");
                for(int i=0;i<array.length;i++){
                    System.out.print(array[i]+" ");
                }
          }
          /**
           * compare and get the time 找出最重一个球所需的次数
           * */
          private static int getMaxWeight(int[] array){
               int result=0;
               /*1 sort: small->big */
    //           sort(array);
               int i=array[0],j=array[1],k=array[2];
               if(i==j&&j==k){
                   result=1+f(i);
               }
               else{
                   /*这里会有区别:这里可以求出得到质量不同球的最大/最小次数:此处求最小次数*/
                   if(f(i)<=f(k))
                      result=1+f(i);
                   else
                      result=1+f(k);
               }
               System.out.println("
    need the least "+result+" times");
               return result;
          }
          /**
           * f():关键的递归回调函数:按照同样的规则逐层求出所需的次数
           * */
          private static int f(int n){
               int result=0;
               if(n==2)
                return 1;
               if(n==1)
                return 0;
               int[] array=new int[3];
               assignGroup(array,n,3);
               result=getMaxWeight(array);
               return result;
          }
          /**
           * sort 排序:按照从小到大的顺序排列数组
           * */
          private static void sort(int[] array){
               /*select sort:选择排序*/
               for(int i=0;i<array.length;i++){
                int min=i;
                for(int j=i+1;j<array.length;j++){
                  if(array[min]>array[j]){
                      min=j;
                  }
                }
                int temp=array[i];
                array[i]=array[min];
                array[min]=temp;
               }
               System.out.println("
    sort result");
               for(int i=0;i<array.length;i++){
                System.out.print(array[i]+" ");
               }
          }
          public static void main(String[] args) {
               System.out.println("please input the ball number:");
               @SuppressWarnings("resource")
               int num=new Scanner(System.in).nextInt();
               int[] array=new int[3];
               if(num>2){
                   assignGroup(array,num,3);
                   getMaxWeight(array);
               }
          }
    }

    明确思路,代码看起来就很简单了。

    执行效果:

    欢迎有不同看法的同仁指正。转载请注明链接。

  • 相关阅读:
    #JVM方法区、堆、栈’#
    #前端# 解决前端页面滑动不顺畅的问题
    【Web协议】服务器推送浏览器:Server-Sent Events(SSE)
    【性能调优】Java程序CPU高定位
    转载 I/O模型:BIO/NIO/AIO 学习
    【性能调优】Java程序内存高定位
    算法--字符串:最长回文子序列
    算法--字符串:最长递增子序列LIS
    算法--字符串:最长回文子串
    算法--字符串:最长公共子序列LCS
  • 原文地址:https://www.cnblogs.com/dftencent/p/5378620.html
Copyright © 2020-2023  润新知