北理工.程序设计方法实践.软工

北理工.程序设计方法实践.效率分析

百丽宫小菜鸡的算法学习记录,谢谢各位提出建议。

效率分析题目分析

5、诸葛兔猜数

在这里插入图片描述
注释:这道题的x表示要猜出的数,n表示上线即右边界(最开始可取)
最少调用意味着每一次循环尽量少调用guess函数

void guessnumber(int n)
{
    int left = 1;
    int right = n;
    int count = 25;
    while(count){
        int mid;
        mid = (right+left)/2;
        if(guess(mid)==1)left = mid;//第一次调用
        else right = mid; 
        if((right-left)<=1){
            if(guess(left))printf("%d\n",left);//第二次调用
            else printf("%d\n",right);
            break;
        }
        count--;
    }
}

该次提交有多个样例没过,guess函数每次调用两次,能否减少每次的调用?

void guessnumber(int n)
{
    int left = 1;
    int right = n+1;
    int count = 25;
    while(count){
        int mid;
        mid = (right+left)/2;
        if(guess(mid)==1)left = mid;//仅调用一次
        else right = mid; 
        if((right-left)<=1){
            printf("%d\n",left);
            break;
        }
        count--;
    }
}

这里有一个细节,为什么当左右边界距离小于1,就可以认为x为left?
因为初始化 right = n + 1;此时右边界与此后每一次都是不可取的了,所以只需要考虑左边界的取值。

6.萝卜三元组

在这里插入图片描述这里的卡的函数调用次数很值得玩味。即

  1. 每次调用不超过3次,且进行n次函数循环。
  2. 进行三次n循环
    这是对3n的理解。
    然后结合这道题,我们知道实际上我们求的最小值,就是找到三个距离最近的点,于是只需要将每次最小的点向后移动再判断就行。
int findMinDiffWeight(int n)
{
    long long ans = 1000000000;
    int i = 0,j = 0,k = 0;
    while(i!=n&&j!=n&&k!=n){
        int temp = DiffWeight(i,j,k);
        if(temp < ans){
            ans = temp;
        }
        int cc = xls_min(i,j,k);
        if(cc==1)i++;
        if(cc==2)j++;
        if(cc==3)k++;
    }
    return ans;
}

实际上是进行了3次n循环;符合第二种思路。

7.白兔让萝卜

在这里插入图片描述这道题有2n个数据。如果进行遍历,则调用了4n次函数。

void findminandmax(int n)
{
    int max = 1;
    int min = 1;
    for(int i = 2; i <= 2*n;i++){
        if(cmp(max,i)==-1)max = i;
        if(cmp(min,i)==1)min = i;
    }
    printf("%d %d\n",min,max);
}

一共调用了4n次,显然无法通过这道题。
于是我在思路不变的情况下进行了一个小优化。

void findminandmax(int n)
{
    int max = 1;
    int min = 1;
    for(int i = 2; i <= 2*n;i++){
        if(cmp(max,i)==-1)max = i;
        else{//这里的改变使得调用次数减少
            if(cmp(min,i)==1)min = i;
        }
    }
    printf("%d %d\n",min,max);
}

这样不需要每一次都进行最小值的比较,**只需要当最大值不变的情况下比较一次就行。**这样的话,调用的次数显然在2n到4n之间,能不能小于3n次还得看后台数据是否赏脸。但是出题的学长显然考虑到了这一点。所以还是有几个测试点没过。
回到题目本身,3n还有一种拆分方法,就是思路一。n次循环,每次循环调用三次。对于2n的个数,显然进行分组即可。

void findminandmax(int n)
{
    int max = 1;
    int min = 1;
    for(int i = 1; i <= 2*n;i+=2){//分组
        int c = cmp(i,i+1);
        if(c ==-1){
            if(cmp(i,min)==-1)min = i;
            if(cmp(i+1,max)==1)max = i+1;
        }
        if(c ==1){
            if(cmp(i+1,min)==-1)min = i+1;
            if(cmp(i,max)==1)max = i;
        }
    }
    printf("%d %d\n",min,max);
}

分组,两两比较,然后大的和max比较,小的和min比较。

8.找大佬

小菜鸡提交了很多次都没过。后来发现这道题有5个测试点的输出都是-1,即没有找到大佬的情况。为什么发现呢,因为输出-1的时候输出了很多次-1,改了这个就过了

void guessdalao(int n)//这一段代码没考虑其他人没他强的那一个循环
{
    int winer[1005];
    int ans = 1;
    for(int i = 2;i <= n;){
        int c = better(ans,i);
        if(c == 1){
            i++;
        }
        if(c==0){
            ans = i;
            i++;
        }
        if(c == -1)return;
    }
    int beat = 0;
    for(int i= 1;i <=n;i++){
        if(i == ans)continue;
        int temp = better(ans,i);
        if(temp==1)beat++;
        if(temp == 0)printf("-1\n");//这里可能出现重复输出-1的情况
    }
    if(beat==n-1)printf("%d\n",ans);
}
void guessdalao(int n)
{
    int ans = 1;
    for(int i = 2;i <= n;){//找到可能为大佬的人
        int c = better(ans,i);
        if(c == 1){
            i++;
        }
        if(c==0){
            ans = i;
            i++;
        }
        if(c == -1)return;
    }
    int beat = 0;//比其他人都强
    for(int i = 1;i <=n;i++){
        if(i == ans)continue;
        int temp = better(ans,i);
        if(temp == 1)beat++;
        if(temp == 0){
            printf("-1\n");
            return;
        }
        if(temp == -1)return;
    }
    int hh = 0;//其他人都没他强
    for(int i = 1;i <= n;i++){
        if(i == ans)continue;
        int temp = better(i,ans);
        if(temp == 0)hh++;
        if(temp == 1){
            printf("-1\n");
            return;
        }
        if(temp == -1)return;
    }
    if(beat == n-1 && hh == n-1)printf("%d\n",ans);
}

找到可能为大佬的思路是,先假设第一个是大佬,和后面的依次比较,如果为0,说明没人家强,那么这个人一定不是大佬,所以将大佬的位置让给比他强的那个人,再在这个新大佬的位置继续向后比较,直到遍历完这n个人。

效率分析总结

该组程序题具有明显的特征即减小时间复杂度(虽然感觉没减少多少),但是分组意识尤其重要。对题目所限制的次数进行理解和总结思路。即对3n的划分:

  1. 每次调用不超过3次,且进行n次函数循环。
  2. 进行三次n循环
  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值