算法导论-时间复杂度理解-抽签

题目:

抽 签

你的朋友提议玩一个游戏:将写有数字的n 个纸片放入口袋中,你可以从口袋中抽取4 次纸
片,每次记下纸片上的数字后都将其放回口袋中。如果这4 个数字的和是m,就是你赢,否
则就是你的朋友赢。你挑战了好几回,结果一次也没赢过,于是怒而撕破口袋,取出所有纸
片,检查自己是否真的有赢的可能性。请你编写一个程序,判断当纸片上所写的数字是k1,
k2, …, kn 时,是否存在抽取4 次和为m 的方案。如果存在,输出Yes;否则,输出No。
限制条件
 1 ≤ n ≤ 50
 1 ≤ m ≤ 108
 1 ≤ ki ≤ 108
输入

n = 3
m = 10
k = {1, 3, 5}
输出
Yes(例如4次抽取的结果是1、1、3、5,和就是10)

分析

这道题咋一看很简单,四重循环暴力枚举即可,对于原题来说,1000ms完全没问题,不过这么简单的题怎么分析呀嘿嘿,听我细细道来,对于一道算法题来说,其正确性第一,其次就是他的时间复杂度了,如果超时,很不行,只能算部分正确……
依据规律,时间限制1000ms,时间复杂度为O(n^2),c语言描述的话,输入百万级别,处理起来游刃有余,输入千万级别,勉勉强强通过,如果处理亿级别,就很悬了,循环体极为简单的的情况下可以通过……对于我们来说,正确性和高效性缺一不可!
这是针对平方阶,对于我们这道抽签的题目来说,最简单想到的算法是O(n4),n=100,运行次数就达到108了,非常恐怖。
请看这个可怕的解法:

 bool flag=false;
 cin>>n>>m;
// 四层循环O(n^4) 
 for(int i=0;i<n;i++)
  cin>>k[i];
 for(int a=0;a<n;a++)
  for(int b=0;b<n;b++)
   for(int c=0;c<n;c++)
    for(int d=0;d<n;d++)
     if(m==k[a]+k[b]+k[c]+k[d])
      flag=true; 

为了让输入更大一些,我们对算法进行改进,原本枚举四个循环求和,如今和我们知道,原来我们判断m=a+b+c+d,如今我们稍微改进,判断m-d=a+b+c,我们把m-d计算出来,花费n的时间存在一个数组中,然后排序花费nlogn的时间,判断的时候用二分查找,在待查找数组中查找三重循环a+b+c的和。时间复杂度就降到了n3logn。这就降低很大一块了。
然后这里还有更快的算法,时间复杂度能至n^2logn,思路是将最里面两重循环化简,判断m-d-c=a+b,将m-d-c计算出来排序好,然后二重循环计算a+b的结果与待排序序列判断。算法非常巧妙的将四重循环拆开,排序再查找。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值