求区间范围最小值最大值  
  用分治法(Divide and Conquer)求n元数组最小元与最大元,当n=1时,不用比较,最大元和最小元都是这个数;当n=2时,一次比较就可以找出两个数据元素的最大元和最小元;当n>2时,可以把n个数据元素分为大致相等的两半,一半有n/2个数据元素,而另一半有n/2个数据元素。先分别找出各自组中的最大元和最小元,然后将两个最大元进行比较,就可得n个元素的最大元;将两个最小元进行比较,就可得n个元素的最小元。

  在规模为n的数据元素集合中找出最大元和最小元, 至少需要3n/2-2次比较,即3n/2-2是找最大最小元算法的下界。当n=2k,或当n≠2k时,若n是若干2的整数幂之和,则算法的时间复杂度仍可达到下界3n/2-2。

a.为一个分治算法编写伪代码,该算法同时求出一个n元数组的最大元素和最小元素的值。
b.请拿该算法与解同样问题的蛮力算法做一个比较。

解答:
a.同时求出最大值和最小值,只需要将原数组一分为二,再使用相同的方法找出这两个部分中的最大值和最小值,然后经过比较就可以得到整个问题的最大值和最小值。

算法 minmax_element(A[l..r], min, max)
// 该算法利用分治技术得到数组A中的最大值和最小值
// 输入:数值数组A[l..r]
// 输出:最小值min和最大值max

if(r<0) return;      // 空数组,没有最大最小元
if(r==0) max=min=A[0]; // 只有一个元素时
if(r==1) {min=A[0]<=A[1]?A[0]:A[1]; max=A[0]<=A[1]?A[1]:A[0];}  // 有两元素时
else
{  
  m=int((l+r)/2);   // 去中间值,把数组分成两个部分
  minmax_element(l, m, fMin, fMax);   // 递归解决前一部分
  minmax_element(m+1, r, sMin, sMax); // 递归解决后一部分
  max= std::max(fMax, sMax); // 从两部分的两个最大值中选择大值
  min= std::min(fMin, sMin); // 从两部分的两个最小值中选择小值
}

为了数据类型一般话,我们采用 C++ 的模板。将最小最大数对存储在 std::pair 类型中。

template<class ForwardIt, class Compare>
std::pair<ForwardIt, ForwardIt> minmax_element(ForwardIt first, ForwardIt last, Compare comp)
{
std::pair<ForwardIt, ForwardIt> result(first, first); if(first == last) return result;
if(++first == last) return result; if(comp(*first, *result.first))
result.first = first;
else
result.second = first; while(++first != last)
{
ForwardIt i = first;
     if(++first == last)
     {
if(comp(*i, *result.first))
result.first = i;
else if (!(comp(*i, *result.second)))
result.second = i;
break;
}
else
{
if(comp(*first, *i))
{
if(comp(*first, *result.first))
result.first = first;
if(!(comp(*i, *result.second)))
result.second = i;
}
else
{
if(comp(*i, *result.first))
result.first = i;
if(!(comp(*first, *result.second)))
result.second = first;
}
}
}
return result;
}

时间复杂度为:
t(n)=2*t(n/2)+2 n>2
t(1)=0 t(2)=1
设n=2^k,则n/2=2^(k-1)
t(n)=t(2^k)=2*t[2^(k-1)]+2
=2[2*t(2^(k-2))+2]+2
=2^2*t[2^(k-2))]+2^2+2
=2^2[2*t[2^(k-3)]+2]+2^2+2
=2^3*t[2^(k-3)]+2^3+2^2+2
=...
=2^(k-1)*t(2)+2^(k-1)+2^(k-2)+...+2   // t(2)=1
=2^(k-1)+2^(k-1)+2^(k-2)+...+2 // 后面部分为等比数列求和
=2^(k-1)+2^k-2    // 2^(k-1)=n/2, 2^k=n
=n/2+n-2
=3*n/2-2

b.蛮力法的算法如下:

算法 simple_minmax(A[0..n])
// 用蛮力法得到数组A的最大值和最小值
// 输入:数值数组A[l..r]
// 输出:最小值min和最大值max

max=min=A[0];
for(i=0; i<n; ++i)
{
  if(A[i]>max) max=A[i];
  if(A[i]<min) min=A[i];
}

蛮力算法的时间复杂度t(n)=2*(n-1)

C++ 的头文件 <algorithm>包含了上面两种算法。
3*n/2-2 对应 std::minmax_element
2*(n-1) 对应std::min_element + std::max_element

算法 minmax_element 的时间复杂度为3*n/2-2,simple_minmax 的时间复杂度为2n-2,都属于Θ(n)复杂度。
但比较可得,minmax_element 减少了不必要的比较
速度上比 simple_minmax 的快一些。

随机推荐

  1. 逆向工程学习第二天--动手开发自己的第一个shellcode

    一个简单的c语言添加windows管理员账号的小程序,之前在渗透的时候经常用到,现在拿它来做自己的第一个shellcode. C代码: #pragma comment(lib, "netap ...

  2. 轮播插件unsilder 源码解析(一)---使用

    啰嗦几句:学习的可以直接省略,一直本着写原生的插件想法,但是前天看了吕大豹的博客觉得自己都没有正经的写个jquery插件:所以在开始写之前我会先对几个比较热门的jquery的插件进行源码分析:至于为什 ...

  3. Mac 配置 php-fpm 时出现'/private/etc/php-fpm.conf': No such file or directory (2)

    https://github.com/musicode/test/issues/5 Mac 自带 php-fpm,在终端执行 php-fpm,会报如下错误: ERROR: failed to open ...

  4. FORM

    一 .新增的input输入属性 1.email类型 在表单提交E-mail地址时,无效的输入会生成很多无效数据,对后期的数据检索造成一定的影响.所以在表单提交之前,需要对输入的E-mail地址进行有效 ...

  5. ASP.NET vNext on CentOS 7

    第一步是在Linux上安装.Net的运行时Mono VNext要求Mono最小版本3.4.1,可怜的centos连低版本的mono都不含.我们只能通过编译来安装.目前最新的版本为3.12 源码下载:h ...

  6. linux glances的基本使用

    一.Glances介绍 glances 是一款用于 Linux.BSD 的开源命令行系统监视工具,它使用 Python 语言开发,能够监视 CPU.负载.内存.磁盘 I/O.网络流量.文件系统.系统温 ...

  7. Adaboost\GBDT\GBRT\组合算法

    Adaboost\GBDT\GBRT\组合算法(龙心尘老师上课笔记) 一.Bagging (并行bootstrap)& Boosting(串行) 随机森林实际上是bagging的思路,而GBD ...

  8. C#进阶目录

    一.Sql语句的性能优化 二.Quartz.NET的介绍 三.Log4.Net的介绍 四.Topshelf的介绍 五.Git的使用 六.IEnumerable接口迭代原理 七.Lambada表达式的演 ...

  9. CI加载model的问题

    1.需求 CI在linux上无法加载model 2.原因 因为linux区分大小写,且model文件名首字符要大写. As said in the comments : Your model's fi ...

  10. AFNetworking 与 gbk 编码格式后台数据的使用

    仅针,后台数据为GBK编码时的AFNetWorking 使用情况: 1. Request failed: unacceptable content-type: text/html     soluti ...