昨晚的笔试题:
大概是这个意思:一个数组X[1,2,....NUM]里面存放NUM个随机数,现在要找出数组里面的最大数和最小数,有min和max两个变量保存结果
一个种思路:遍历数组,把每个元素和关键字比较,每次都要把元素和min和max比较
第二种思路:如果一个数比min小就不可能比max大,不用再和max比较,如果比max大则不会比min小,不再和min比较
题目是给代码的,大概意思就这样,问的是第二种代码比第一种代码平均减少了多少次比较,写出推导过程晚上要去面试,估计会问这道题目(我没做!),求答案和推导过程(我觉得能平均减少NUM/2次数)

解决方案 »

  1.   

    #include<stdio.h>
    #include<stdlib.h>void main()
    {
       int num[20];//用来存放随机产生的20个数
       int i,j,sum,max,min,average;//sum,max,min,average分别用来存放总和,最大,最小及平均值
     srand(100);
     for(i=0;i<20;i++)
     num[i]=rand()%100+1;
     max=num[0];
     min=num[0];
     sum=0;
     for(i=0;i<20;i++)
     { if(max<mun[i]) max=num[i];
       if(min>num[i]) min=num[i];
       sum=sum+num[i];
     }
     average=sum/20.0;
     j=1;
     for(i=0;i<20;i++)//输出20个数,5个一行
     { printf("%d  ",num[i]);
       j++;
       if(j==5) printf("/n");
     }
    printf("最大值为:%d,最小值为:%d,平均值为:%f",max,min,average);
      pringf("/n");
    }
      

  2.   

    第一种思路是2*NUM的比较次数,这个应该没什么疑问。
    第二种思路,我对题意并不是很了解,要么先比较min要么先比较max,你的意思是先随机比较哪个么?
      

  3.   

    找出数组里面的最大数和最小数不是有方法么?min=X.Min();
    max=X.Max();
      

  4.   

    这算是考算法复杂度么?
    若原先需要比较2 * NUM次
    那么最少只用比NUM次,最多还是2 * NUM
    则答案是NUM/2
      

  5.   

    这回答太没逻辑了...
    最少a次,最多b次,平均就一定是(a+b)/2次么...
    又不是线性分布的
      

  6.   

    第一种不管怎么样都是要比较 2*Num次
    第二种就是第一种的优化
    最少比较Num次,最多比较2*Num次
    平均不知道怎么算啊
    难道是(Num + 2*Num )/2??
      

  7.   

    第一种:(num-1)*2
    第二种:(num-1)*1用编程方式来表示就是:
    min=max=array[0];
    for(int i=1;i<array.Length;i++)
    第一种:if(array[i]<min) min=array[i];if(array[i]>max)max=array[i];
    第二种:if(array[i]<min) min=array[i];else if(array[i]>max)max=array[i];
      

  8.   

    第二种应该是 (num-1)*1.5 else if是有50%执行机会的
      

  9.   

    第一种每个都要和Max min比较就是2*Num
    第二种每个最少比较一次,最多两次 即Num~2*Num 
    结果
      

  10.   

    写了个程序测试了下的确是少了NUM/2,但是很难严格论证。
    比如楼上的解答,为什么else if 是50%执行的?这就很难解释清楚。
    楼主面试的话可以提出另外一种算法,因为这种方法是不稳定地减少NUM/2的比较次数。
    有一种算法是稳定地减少NUM/2的比较次数:
    每次取2个数,比如A和B,比较A和B,拿小的和min比较,拿大的和max比较。
    这样NUM个数分成NUM/2个组,每个组比较3次,这样也能减少NUM/2的比较次数
      

  11.   

    严重不同意15楼的说法
    1、数字array[i]要么执行if要么执行else if,各占50%的概率
    2、减少次数是不稳定,所以求的是一个概率
    3、每次取2个数,多了2个比较:a)判断是否还存在2个数;b)比较A和B
      

  12.   

    第一种方法:先区前2个数做下比大小,1次 后面的比较次数该是(num-2)*2,总共1+(num-2)*2
    第二种方法:先区前2个数做下比大小,1次,后面最理想的次数是(num-2),最不理想的次数是(num-2)*2比较次数num-1~2*num-3
    结果是0~num-2次
      

  13.   

    1.笑了
    要么执行if 要么执行else if 各占50的概率...
    if( rand % 10 < 1) {...}
    else {...}
    我是不是可以说要么执行if 要么执行else,各占50%的概率?
    2.我没说这个不好
    3.你就不能从第一第二个开始比较么,何须知道剩下的有多少个数
    比较A和B根本不会浪费比较次数。
      

  14.   

    支持这个
    LZ所述这样优化其实可能只是加了一个continue;
    确实有更好的优化方式比如15L        
    static void Main(string[] args)
            {
                int[] array = new int[10];
                Random r = new Random();
                for (int i = 0; i < array.Length; i++)
                {
                    array[i] = r.Next(100);
                    Console.Write(array[i] + " ");
                }
                int max = array[0];
                int min = array[0];
                int count = 0;            Console.WriteLine();
                for (int i = 1; i < array.Length; i++)
                {
                    count++;
                    if (array[i] < min)
                    {
                        min = array[i];
                        continue;//其实就是这样优化了一个continue
                    }
                    count++;
                    if (array[i] > max)
                    {
                        max = array[i];
                    }
                }
                Console.WriteLine("Max={0} Min={1} count={2}", max, min, count);
                Console.ReadKey();
            }
    我自己测试时候的代码既然题目给出了代码 那么代码1的执行次数
    是 Num*2 还是 (Num-1)*2 还是17楼所述 1+(num-2)*2 LZ一看便知
    那么其实这个题就是要算概率问题
    这非常赞同16楼的第二条观点
    不过肯定不是简单的50% 数学不行 继续关注此帖
      

  15.   

    对于找最小值,最多替换 Min 值 Num 次,最少替换 1 次。平均 (Num + 1)/2
    对于找最大值,最多替换 Max 值 Num 次,最少替换 1 次。平均 (Num + 1)/2替换最小值后,就不再去和最大值比较。
    替换最大值后,就不再去和最小值比较。
    但是这两个条件有先后,只能选择其中一种作为算法。无论选择哪种,都能比原来省下 (Num + 1)/2 次比较。
      

  16.   

    唉,对于说以下语句不是各占50%概率的说法,我真对你们的智商表示担忧!!!
    if(array[i]<min){}else if(array[i]>max){}啥都不说了。
      

  17.   

    array[i]<minarray[i] 是一个随意的数 平凡的数  
    比如你110跨栏的时间 或者我110跨栏的时间
    min是一个  特定的数  他比较了i-1个数 才成就了这个min 
    比如刘翔110跨栏的时间你说array[i]有50%的可能性比min小?
      

  18.   

    我想说说我的看法,,
    题目里面的if (next<min)
    {
      noNeedCompareMin();
    }
    if (next>max)
    {
       noNeedCompareMax();
    }
    以先比较最小的为例,如果这个数比当前最小的还要小,自然它会是当前最小的,所以没必要比较最大值了,,
    但是如果是比当前最小的要大,那么至于它是不是比最大值要大,第二个判断都是要做的,(next>max)..
    对于先比较max也是同理。。所以减少的次数就只需要考虑一种情况,是这样。 比如 我们取第一个数当做最小数,那么只有后面的数比前面的最小数还要小的时候那就会有一次比较被节省下。
    所以我们认为随即数任何两两大小都是50%的机会
    那么 第二个数比第一个数小的概率就是1/2,
    第三格数比前面2个最小数还要小的概率就是1/3,
    同理对于M个随机数那么节省的次数就是
    1/2+1/3+1/4+...+1/M
      

  19.   

    我对你概率论掌握情况也表示担忧!
    这题从结果来说的确是NUM/2没错,但你想当然的论证显然不能在面试中获得好的评分
      

  20.   

    亲爱的同学们,我们说的不是随机数的概率,而是执行 if ... else if ... 的概率!!!!array[i] 是个随机数,它只有2种可能:a)小于min,b)大于等于min这2种情况的概率各占 50%如果小于min,则不执行 else if,否则执行 else if而面试题问的是执行比较的次数,也就是执行if的判断和else if的判断的次数,并非判断成功的次数我说的这么清楚你们是否应该有点醒悟!!!
      

  21.   


    array[i] 是个随机数,它只有2种可能:a)小于min,b)大于等于min这我笑了 如果MIN 是3, max 7 那么请问 如果现在array[i]  =4  , 天神下降了竟然会出现4这个第三种情况
      

  22.   

    题中第一种方法执行 if... if...的概率是 100%+100%,因为是2个并行的if
    第二种执行 if...else if... 的概率 100%+50% 解析过程如下:if (array[i]<min){//100%执行这个比较}else{//50%的情况执行else,因为是随机数,要么比min小,要么比min大(包括等于)
        if(array[i]>max){ }//100%执行这个比较(别忘了这个100%包含在50%的可能里)
    }
    //执行比较语句的次数:100%+50%*100%
      

  23.   


    兄弟、你上面的写法是,
    if(array[i]<min){}else if(array[i]>max){}
    你现在改口说这个a)小于min,b)大于等于min
    我读不懂你的意思了
      

  24.   

    回复 #33, #34如果你看的重点是 if 中的判断,说明你已经 OUT 了,#31 楼能让你从痛苦中解脱,如果你认真看的话
      

  25.   


    我承认我不止一次的读错你的意思了。。
    不过你要认为第i次数字 比前面最小的数值的大小概率如果是50%的话,那我真是汗了。
    请你也看下24楼的我补充说24我的意思,再第二个if前面加一个else忘记写了如果第一个题目是2M的比较的话,
    那么第二个题目是1/2+1/3+1/4+...+1/M
      

  26.   

    你如何证明array[i]<min的概率是50%呢
      

  27.   

    我觉得这个主要问题是怎么把推导过程写清楚。
    num/2吧,但我也不会写推导过程。
      

  28.   

    恩 俗称的牛角尖 #39的疑问:你如何证明array[i]<min的概率是50%呢在#18 #23包括后面好几个楼都解释了 可惜啊我觉得#24听起来很有道理
      

  29.   

    计算时间复杂度
    1  2*n
    2 应该算是是二分法查找,两次 2*log2(n)节约的时间就是 2*n - 2*log2(n)数据结构的书上应该有算时间复杂度的,记不清了
      

  30.   

    多谢支持啊。。 
    这个题目也就变成了另外一个题目。一串随机数,在第i数是前面数字的最小数的概率是多少的问题了。 我认为随机数之间22平等,所以是1/i
    所以就得出会节省的判断次数是
    1/2+1/3+...1/M 
      

  31.   

    优化了:(1+1/2+1/3+1/4+1/5+1/6+...1/n)/n 
    当n很大时,括号里的部分就成了0.57721566490153286060651209叫做欧拉常数很多人都说优化了(n-1)/2之类的
    你们太大看这个优化的效果了这题确实可以写出优化(n-1)/2的代码但是题目给出的那种优化方案优化不了那么多
      

  32.   

    LS写错掉了 应该优化了:
    (1/2+1/3+1/4+1/5+1/6+...1/n)/n  
    (1/2+1/3+1/4+1/5+1/6+...1/n)=0.57721566490153286060651209+   ln-1哎呀数学还给老师了 其实不完全理解
      

  33.   

                var max = 0;
                var min = 0;
                var vcount = 0;
                var flag = false;
                var count = array.Length;
                for (var i = 0; i < count / 2; i++)
                {
                    vcount += 1;
                    if (!flag)
                    {
                        max = array[i] > array[count - i - 1] ? array[i] : array[count - i - 1];
                        min = array[i] < array[count - i - 1] ? array[i] : array[count - i - 1];
                        flag = true;
                        vcount += 2;                }
                    else
                    {
                        vcount += 1;
                        if (array[i] > array[count - i - 1])
                        {
                            max = array[i] > max ? array[i] : max;
                            min = array[count - i - 1] < min ? array[count - i - 1] : min;
                            vcount += 2;
                        }
                        else
                        {
                            max = array[count - i - 1] > max ? array[count - i - 1] : max;
                            min = array[i] < min ? array[i] : min;
                            vcount += 2;
                        }
                    }
                }
                vcount += 1; 
                if (count % 2 != 0)
                {
                    vcount += 2; 
                    max = array[count / 2] > max ? array[count / 2] : max;
                    min = array[count / 2] < min ? array[count / 2] : min;
                }
                Console.WriteLine(string.Format("max:{0} min:{1} vcount:{2}", max.ToString(), min.ToString(),vcount.ToString()));
      

  34.   

    第一种方法要做2*(NUM-1)次比较。
    第二种方法,如果以
    min = X[i];
    max = X[i];
    for(i =1;...)
    {
    if(X[i]<min)
    {
        min = X[i];
    }
    else if(X[i]>max)
    {
        max= X[i];
    }
    }这种形式比较。
    得看数组里面最小值的位置,如果最小值在第一个,if语句每次都不true,都要对else if比较,总次数也是
    2*(NUM-1),这是最差的情况;
    如果数组是以降序排列,if语句每次都是true,那么只要进行(NUM-1)次比较,少了(NUM-1);
    再看,如果最小的值出现在中间第n个数处,那么从中间以后的数都要比较2次,后的比较次数为2*(NUM-n),但此时第n个前面的比较次数在(n-2)与2*(n-2)之间,与前面几个数中的最小值的分布有关。
    由此看出,应该不是  NUM/2。
    应该用数学归纳法来计算!
    先吃饭去了
      

  35.   

    应该比NUM/2小,应该降序排列的概率更小
      

  36.   

    感觉楼上的说得是正确的。
    13L认为if(min<array[i]){}会被执行的概率是50%啊,第i个数只是要跟得到的min比较。这里只会有2种可能性,一种是比他大,一种是比他小。所以是50%啊。
    楼上的是说第i个数为这第i个数中的最小值的概率是1/i。所以当他是最小值时,min过来的时候才不会去去执行else if这段代码。所以概率是1/i.
    头晕,感觉是13L说得也是有点道理的。
      

  37.   

    else if执行的概率不是50%,这得看数组里面最小值的分布,如果最小值在第n个数,则n后面的数都需要执行
    else if,但是这个并不是说第n个前面的数都不执行else if,这得看第1到第n个数中,局部最小值的位置。
    假如第1到第n个数是升序排列,那每次都会执行else if。
      

  38.   

    min = X[i];
    max = X[i];
    for(i =1;...)
    {
    if(X[i]<min)
    {
      min = X[i];
    }
    else if(X[i]>max)
    {
      max= X[i];
    }
    }
    以这种方式为方便起见,min是一个很大的数,max为一很小的数
    num个数中,最小值的分布概率在各位置都是1/num
    最小数在的位置       少的次数
    1                        f(1)=1
    2                        f(2) = 1   +  1
    3                        f(3) = 1/2概率为f(2) +  1/2概率为f(1) + 1
    .
    .
    .
    n                        f(n) = (f(n-1) + f(n-2)+....+f(1))/(n-1) +1
    .
    .
    .
    num                      f(num) = (f(num-1)+f(fun-2)+...+f(1))/(num-1)+1
    每个都是1/num概率
    求和得到平均少的次数
    sum = (f(1)+f(2)+f(3)+...+f(num))/num
      

  39.   

    //min = 1000;
    //max = 0;
    for(i =1;...)
    {
    if(X[i]<min)
    {
      min = X[i];
    }
    else if(X[i]>max)
    {
      max= X[i];
    }
    }
    以这种方式为方便起见,min是一个很大的数,max为一很小的数
    num个数中,最小值的分布概率在各位置都是1/num
    最小数在的位置 少的次数
    1 f(1)=1
    2 f(2) = 1 + 1
    3 f(3) = 1/2概率为f(2) + 1/2概率为f(1) + 1
    .
    .
    .
    n f(n) = (f(n-1) + f(n-2)+....+f(1))/(n-1) +1
    .
    .
    .
    num f(num) = (f(num-1)+f(fun-2)+...+f(1))/(num-1)+1
    每个都是1/num概率
    求和得到平均少的次数
    sum = (f(1)+f(2)+f(3)+...+f(num))/num
      

  40.   

    假如随机数是范围是 1到10000;
    如果min = 5;
    然后来判断 if(  x< 5) 基本不能true,也就是说要再执行else if,else if执行的概率当然不是50%另外,我这种说法只是反驳了你
    但是数组是一开始就分布好的,并不是随机得到一个再比较一个的。
    你这种思维方式是的不到答案的
      

  41.   

    不用纠结了。我们不是来证明sq_zhuyi不对的,我想作为随机数,每个数的大小都是概率是均等的,那么这题目的平均减少量就是1/2+1/3+...1/m
      

  42.   

    以先比较小后比较大的为例, 也就是if(arrary[1]<min) else if(array[i]>max)
    也就是举例3个数字1,2,3
    那么这三个数字排列组合后是3!=6种
    1,2,3    ---这种情况,第一个数字就是最小数了后面没有比它小的 就没有节省的次数。以下同理
    1,3,2    --- 节省数 0
    2,1,3    ---1
    2,3,1    ---1
    3,2,1    ---2
    3,1,2    ---16种情况总共可以节省5次那么请问是不是平均节省了5/6次呢。 不知道楼上的直接算是咋算出来的
      

  43.   

    我懂了, 你跟我的比较方法有点不同
    你的min 一开始就是第一个数,而我的方法min一开始是一个很大的数,所以
    1,2,3 ---这种情况,按照我的方法也是减少一次。
    我一开始没看你在24楼的回答,所以没能完全理解你的算法。你这个答案是对的,只不过我们的比较方法不同。我刚刚按照我算的方法,如果min 一开始等于第一个数,得到的答案是与你一样的。
    我的思路是先得到一个序列,然后假设最小值在每个位置的概率都是1/n,然后用数学归纳法算出来的。
    更改下我的算法,如果min = 第一个数
    最小数在的位置    减少的次数
    1               f(1)=0
    2               f(2) = 0 + 1
    3               f(3) = 1/2概率为f(2) + 1/2概率为f(1) + 1
    .
    .
    .
    n               f(n) = (f(n-1) + f(n-2)+....+f(1))/(n-1) +1
    .
    .
    .
    num             f(num) = (f(num-1)+f(fun-2)+...+f(1))/(num-1)+1
    每个都是1/num概率
    求和得到平均少的次数
    sum = (f(1)+f(2)+f(3)+...+f(num))/num
      

  44.   

    第一有2N个比较
    第一次,每一个数在进行比较前有3中情况:比MAX大,比MIN小,中间值。
    现在解释先与MAX比较,在于MIN比较
    if(num>max)
      一次比较 //随机数,3分一得概率
    if(num<max)
     二次比较因此,n/3+2*n/3 = n减少了一半的比较时间
      

  45.   

    楼主,第二个思路从算法上看,有问题!
    当数组中的元素为从小到大或从大到小排列时,会出问题。
    举个例子:若数组x[NUM]里数据为{5,4,3,2,1},设初始条件为min=10,max=0。
    则按楼主的第二个思路运算下来,得到的结果为min=1,max=1。是不是算法上本身就存在问题呢?
      

  46.   

    你没看懂题目,第二种思路是如果当前值取代了最小或者最大值就没有必要再和另外的在比较
    如果值介于max和min还是要2个都比较的
      

  47.   

    面试的考官说了答案不是Num/2;说答案在《编程珠玑》
    过2天去图书馆借来看看!
    明天终面啊,祝自己好运!
      

  48.   

    对于2来说,最坏情况,a[1]是最小,a[2]是最大,这样[3]开始到[NUM]的比较次数都和1一样,由于代码里是先判断最小再判断最大,所以[2]的时候也要执行2次,也就是最坏2和1一样需要比较2num次
    而最好情况是按从大到小顺序排序,这样除了第一次需要比较2次外,后面都是一次比较1次,这样就是num+1次。
    这样2比1的最小和最大差距就是 2num - 2num = 0 和 2num-(num+1) = num - 1.
    平均就是 (0 + 1 + 2 + ... + (num  - 1)) / num
    解就是(Num-1)/2
      

  49.   

    只能给出一个大概的值,因为的出来的结果,在这个范围内都有可能(0----sum/2)
    甚至这不是线性的。所以问平均减少多少次,无法回答。给他解析就行。
      

  50.   

    第一种:各N次,加起来2*N次
    第二种:由于第一种方法每次都要与MAX与MIN比较,而第二种方法只要与其中一个比较就不需要与另一个比较了,所以每次比较就少了一次,N次下去就少N个比较,所以第二种方法的比较次数是N次。
    终上所述,第二种方法比较第一种方法少2*N-N 次
      

  51.   

    我怎么觉得第一种思路是2N;
    第二种思路是N+(N+1)/2;
    首先必须比较一次,假设先比较最小值,次数为N,第二次是否比较在于用多少次找到真正的最小值,根据每一次去数的概率都是1/N,求期望次数,可得:(1+2++N)*(1/N)=(N+1)/2,就是说平均(N+1)/2次比较才能找到最小值,这时不用和最大值比较;
    不知道这种思路对不对,我数学也没学好。
      

  52.   

    第1种方法是2n次,
    第2种方法首先不管和min还是max比较,假定这里和min比较,进行n次,然后有1/2的概率要和max比较,所以是n+n/2 = 1.5n我认为是0.5n次
      

  53.   

    下面我写的这个程序哪里有错,测试结果显示两种方法相差不多,和期望值n/2很大差距~
    "java"
        public class Test4 {
    private static Random ran;
    private int[] source;
    private int min = 0;
    private int max = 0;
    private int compareCount = 0;

    static{
    ran = new Random();
    }
    public static void main(String...args){
    Test4 t = new Test4();
    t.init();
    // t.printRan();
    t.findMinMax(0);//2000
    t.print();
    t.findMinMax(1);//199X
    t.print();
    }
    private void printRan() {
    for(int i : source){
    System.out.println(i);
    }
    }
    private void init(){
    //here I give 1000 numbers to test
    source = new int[1000];
    for(int i=0;i<source.length;i++){
    source[i] = this.geneInt();
    }

    }
    private int geneInt(){
    return ran.nextInt();
    }

    private void print(){
    System.out.println("Min:"+this.min);
    System.out.println("Max:"+this.max);
    System.out.println("compareCount:"+this.compareCount);
    }
    private int getBig(int a,int b){
    this.compareCount++;
    return a>b?a:b;
    }
    private int getSmall(int a, int b){
    this.compareCount++;
    return a<b ?a:b;
    }
    /**
     * @param mode 0 means if a is large than max, no need to compare with min, so vice versa
     */
    private void findMinMax(int mode){
    this.min = source[0];
    this.max = source[0];
    this.compareCount = 0;

    if(mode==0){
    for(int a: source){
    this.max = this.getBig(a, this.max);
    this.min = this.getSmall(a, this.min);
    }
    }
    if(mode==1){
    for(int a: source){
    if(this.max<this.getBig(a, this.max)){
    this.max = a;
    }else if(this.min>this.getSmall(a, this.min)){
    this.min = a;
    }
    }
    }
    }
    }
      

  54.   

    答案不是n/2
    我知道哪里错了, 
    假定先和max比较,则max越来越大,那么越往后面比较,则数比max大的概率要小于比max小的概率,并不是1/2的概率。至于怎么算,目前还不知道