跳跃回溯____寻找最长平台
已知一个已经从小到大排序的数组,这个数组中的一个平台就是连续的一串值相同的元素。例如在1,2,2,3,3,3,4,5,5,6中1, 2.2, 3.3.3, 4, 5.5, 6都是平台。尝试编写一个程序,接受一个从小到大排好序的数组,把这个数组中最长的平台找出来。例如,在上面的例子中,3.3.3就是这个数组最长的平台。
以下内容转载至:http://hxraid.iteye.com/blog/655389
1、经典最长平台算法
已知一个已经从小到大排序的数组,这个数组中的一个平台(Plateau)就是连续的一串值相同的元素 ,并且这一串元素不能再延伸。例如,在 1,2,2,3,3,3,4,5,5,6中[1]、[2,2]、[3,3,3]、[4]、[5,5]、[6]都是平台。是编写一个程序,接受一个数组,把这个数组中最长的平台找出来。在上面的例子中3,3,3就是该数组中最长的平台。
【说明】
这个程序十分简单,但是要编写好却不容易,因此在编写程序时应该考虑下面几点:
(1) 使用的变量越少越好;
(2) 把数组的元素每一个都只查一次就得到结果;
(3) 程序语句也要越少越好。
这个问题曾经困扰过David Gries 这位知名的计算机科学家。本题与解答取自David Gries 编写的有关程序设计的专著。
#include <stdio.h> int longest_plateau() {int x[] = { 3, 4, 4, 7, 8, 9, 9, 9, 9, 10};int n = sizeof(x)/sizeof(int);int length = 1; /* plateau length >= 1. */int i;for (i = 1; i < n; i++)if (x[i] == x[i-length])length++;return length; }
这是一个时间复杂度为O(n) 的经典算法,其代码十分简练。
另外,我自己也写了一个时间复杂度为O(n)的算法,原理就是找出所有平台分界位置,后一个位置减前一个位置(平台长度)的最大值。
int longest_plateau(){int keys[] = {3, 4, 4, 7, 8, 9, 9, 9, 9, 10};int size = sizeof(keys)/sizeof(int);int maxLength=0; //记录最大的平台长度int maxLowBound=-1; //记录最大平台的首偏移int maxHighBound=-1; //记录最大平台的尾偏移int index=1; // 两个分界点位置进行一次比较,index=0或1int bound[2]; //记录每一次比较长度的首,尾偏移 bound[0]=1;//第一个平台的首偏移在数组第0个位置for(int i=1;i<size;i++){if(keys[i]!=keys[i-1]){bound[index++]=i; //当前平台的尾偏移(即下一个平台的首偏移) }if(index==2){ //比较平台长度if(bound[1]-bound[0]>maxLength){maxLength=bound[1]-bound[0];maxLowBound=bound[0];maxHighBound=bound[1];}bound[0]=bound[1]; //当前平台的尾偏移成为下一个平台的首偏移index=1; //准备记录下一个平台的尾偏移到Bound[1]上 }}// printf("longest plat's length is %d\n",maxLength); // printf("longest plat is "); // for(int j=maxLowBound;j<maxHighBound;j++){ // printf("%d",keys[j]); // }return maxLength; }
2、改进的最长平台算法
上面O(n)的时间复杂度级别已经很不错了,但是如果n值特别大,那么仍然要比较n次才可以出结果,我们能不能降低比较次数呢?显然,这个问题是可以优化的。
我们再来回顾一下David Gries的经典算法(代码1的line: 9),不管当前最长平台的长度为多少,每一次比较都是i++。难道每一次比较都是必须的吗? 比如下面这个平台串:
pArr[]: 1 1 1 2 2 2 2 2 3 3 4 4 5 5
index: 0 1 2 3 4 5 6 7 8 9 10 11 12 13
分析: 当pArr[2]==pArr[0]的时候,最长平台长度已经增到了3。此时继续比较pArr[3]==pArr[0]发现不相等。那么说明pArr[3]已经开始了一个新的平台。依据经典算法,我们还要继续比较pArr[4]==pArr[1],pArr[5]==pArr[2]。显然,这两个比较是不必要的,因为pArr[3]开始了新的平台,位置3之前的所有数据都不会和3之后的所有数据相等了。
根据上面的分析,我们很容易的想到可以跳跃一定的次数进行比较,跳跃多少呢?最简单的想法就是跳跃一个当前的longest(最长平台长度)。因为如果当前pArr[index]==pArr[index+longest]的话,说明当前平台长度比上一次的longest还要长,如果pArr[index]!=pArr[index+longest]的话,那么目前的平台长度绝对不会超过longest,也就没有必要再去比较小于longest的平台长度是多少了。
问题并没有想象的那么简单,跳跃longest长度之后,为了下一次还能够跳跃longest长度,有的时候是需要回溯一段距离的。 我们来看看下面的详细算法分析。
还是上面的例子,我们来一步一步的研究这个改进的算法。
(1) 首先计算第一个平台 "1 1 1" 得到了当前最长平台长度为longest=3,当前串位置index=3。
(2) 这时我们比较pArr[index]==pArr[index+longest](即比较pArr[3]<->pArr[6])。显然相等,那么longest++(即longest=4)。然后继续循环比较pArr[index]==pArr[index+longest],直到不相等为止。此时index=8, longest=5.
(3) 这一步非常重要,当前的index=8已近开始了一个新的平台, 而当前的longest=5。继续比较pArr[index]==pArr[index+longest](即比较pArr[8]<->pArr[13]),发现不相等。此时我们能不能继续从pArr[13]开始向后跳跃longest=5的长度呢。显然不对,因为pArr[13]并不是平台5的开始位置,pArr[12]=5。如果跳跃longest长度,后面的计算结果将全部错误。 此时,我们必须从13开始回头遍历,直到找到平台的其实位置pArr[12],然后从12位置开始跳跃longest=5的长度才可以。
//跳跃最长平台算法 int jump_longest_plateau(int * pArr, int size){int longest=1; //最长平台长度int index=1; //平台串位置索引//计算第一个平台的长度for(;index<size&&pArr[index]==pArr[index-1];index++,count++)++longest;//跳跃longest比较平台长度while((index+longest)<size){// 如果跳跃之后相等,则循环继续增大最长平台的长度if(pArr[index]==pArr[index+longest]){while(pArr[index]==pArr[index+longest]){++longest;}index+=longest;}else{ //如果跳跃之后不相等,则回溯寻找当前平台的起始位置index+=longest;for(;pArr[index]==pArr[index-1];index--);}}return longest; }
算法分析:时间复杂度仍然是O(n)级别 (注意:不要看到双重循环就认为是O(n^2)级别)。随然有的时候需要回溯到平台的起始位置,但改进之后的算法仍然降低了比较次数。 因为跳跃longest后最多需要回溯longest-1次(此时共比较longest次)。也就是最差情况下位置index每次跳跃之后都会回溯到index+1的位置上,因此最差情况下改进算法会蜕化成经典算法的比较次数n。
我们列举出一个最差情况的平台串: 1 1 2 2 3 3 4 4 5 5 6 6 7 7 ....
平均而言,1000个长度的随机初始化平台串,改进算法的比较次数在149次左右。而经典算法必须比较1000次。
我的渣渣代码:#include <stdio.h> #include <stdlib.h> #include <string.h> #include <math.h>void fun(int array[],int arraySize) {int numMax, num, timesMax, times, i;for(i = 1, num = numMax = array[0], times = timesMax = 1; i < arraySize; i++){if( array[i] == num )times++;else{if( times > timesMax){numMax = num;timesMax = times;}times = 1;num = array[i];}}printf("timesMax:%d numMax:%d\n", timesMax, numMax); } int main() {int a1[] = {1,2,2,3,3,3,4,5,5,6};fun(a1, sizeof(a1)/sizeof(a1[0])); return 0; }
转载于:https://www.cnblogs.com/wwjyt/archive/2013/02/24/3153120.html
跳跃回溯____寻找最长平台相关推荐
- 数组的最长平台c语言,2010台湾省C语言版高级
1.我们用l代表最长平台的长度,用k指示最长平台在数组b中的起始位置(下标).用j记住局部平台的起始位置,用i指示扫描b数组的下标,i从0开始,依次和后续元素比较,若局部平台长度(i-j)大于l时,则 ...
- 怎么判断一个字符串的最长回文子串是否在头尾_每日一道算法题,让你的头脑更活跃(寻找最长回文子串)...
前言 最近准备把算法慢慢的捡起来,所以准备日更一道算法题目,难度自然是由简入难,所以同学们可以每天都来看看小编的更新. 日更时间定在每晚20:00,希望大家多多关注啦. 昨天就欠更了,简直就是打脸.过 ...
- 1.9 编程基础之二分查找 12 最长平台 python
http://noi.openjudge.cn/ch0109/12/ """1.9 编程基础之二分查找 12 最长平台 http://noi.openjudge.cn/c ...
- 信息学奥赛一本通 1116:最长平台 | OpenJudge NOI 1.9 12:最长平台 | 洛谷 B2097 最长平台
[题目链接] ybt 1116:最长平台 OpenJudge NOI 1.9 12:最长平台 洛谷 B2097 最长平台 [题目考点] 1. 数组中做统计 2. 求最大值 [解题思路] 解法1:遍历并 ...
- 信息学奥赛一本通(1116:最长平台)
1116:最长平台 时间限制: 1000 ms 内存限制: 65536 KB 提交数: 48810 通过数: 16449 [题目描述] 已知一个已经从小到大排序的数组,这个数组 ...
- 最长平台(信息学奥赛一本通-T1116)
[题目描述] 已知一个已经从小到大排序的数组,这个数组的一个平台(Plateau)就是连续的一串值相同的元素,并且这一串元素不能再延伸.例如,在 1,2,2,3,3,3,4,5,5,6中1,2-2,3 ...
- Unity2D游戏使游戏角色跳跃的脚本(包括长按跳跃加成)
首先实现跳跃是在已经实现游戏角色左右移动的基础上 实现游戏角色移动的脚本 在脚本完成后需要将图层设置为Ground,使代码知道地面是哪一个图层. using System.Collections; u ...
- 最长不重复子串python_寻找最长不重复子串
寻找最长不重复子串 Longest Substring Without Repeating Characters Given a string, find the length of the long ...
- 基于回溯法寻找哈密顿回路
基于回溯法寻找哈密顿回路 回溯法是一种选优搜索法,又称为试探法,按选优条件向前搜索,以达到目标.但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯 ...
最新文章
- 图十字链表并求度c语言,利用十字链表存储树结构(便于同时求出某一点的入度与出度)------C语言实现...
- vue本地上传并预览php,vue.js 实现图片本地预览 裁剪 压缩 上传功能
- golang中并发sync和channel
- 【完结】给新手的12大深度学习开源框架快速入门项目
- 启明云端分享|ESP32/ESP8266 烧录器 USB-TTL转接板开发工具ESP-T01的使用教程,视频可参考B站
- 电气:需求响应:初始化一个调度周期的可转入转出负荷(python实现)
- c# WinForm英雄联盟挂机源码及实现原理
- 【Django】django使用原生SQL的方法(附加说说为什么ORM上不了大台面)
- 用户表如何区分普通用户和管理员_Gate.io 比特百科:什么是ETH 2.0及普通用户如何参与ETH 2.0质押挖矿...
- ElasticSearch 索引、更新和删除数据
- c++ 构造函数数组_“动态数组”的设计与实现
- 点击头像显示大图Dialog
- class matplotlib.figure.Figure
- delphi连接sql server的字符串2011-10-11 16:07
- php mian函数,电脑main什么意思
- VB创建超链接 打开指定网站的几种方法
- HP 瘦客户机 - 使用 ie4uinit.exe 应用时,Citrix HDX Flash 出现故障和错误
- win10计算机管理字体糊,win10字体发虚模糊正确解决方法(5个方法)
- Latex IEEEtran第一次总结
- win10配置免密登录linux(centos7)
热门文章
- CentOS 7 搭建 Ceph 集群(nautilus 版本)
- Linux删除文件夹的方法
- Windows下后台运行cmd启动的程序
- Oracle 中data与timstamp互转
- Nginx启动报[10013]错误
- Linux下Tomcat指定JDK和设置内存大小
- Bootstrap tab页签刷新加载不显示,只有点击其他标签后第一个才显示
- 如何在电脑手机间互传文件?
- java getnextentry_java.util.zip.ZipInputStream.getNextEntry()方法示例
- 解决fullgc_CMS发生FullGc分析