线性查找-数组最大距离
2014-01-02 10:11
260 查看
已知整型数组A
, 问找到最大的 j-i, 符合A[i] < A[j].
方法一:n个数据,两个变量,由于当i,j确定时,每次的比较很简单(A[i] ? A[j]),时间为O(1),所以最原始的暴力解法就是时间O(n^2)。
方法二:我们试着逐步降低时间复杂度。对于符合条件 A[i] < A[j]的 i 和 j,j-i 的可能取值范围为[1,n)。 由于必然存在一个极大值k = j-i, 当j-i > k时, 没有 j-i 符合条件;当j-i < k时,必有 j-i 符合条件(比如k序列的子序列)。所以k是在一个线性分布上的极大值,符合二分查找的应用条件。总的时间复杂度为O(n*lgn)
![](http://img.blog.csdn.net/20140102092727796?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdGVhc3ByaW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
图一,A[] = {3,1,2,3,1,2,1}
如上图所示,我们有原始数组A[] = {3,1,2,3,1,2,1}, 纵坐标Rmax[i]表示的是从A[i]到最右边剩余数组中的最大值。如果我们从左边i=0开始,每次比较A[i] 和 Rmax[j] (i<j), 当A[i] < Rmax[j], 向右移动j, 当A[i] < Rmax[j] 刚刚不成立时,j-1-i即是A[0]到A[j]之间符合条件的最大j-i。因为如果有x<i, 能够符合A[x] < A[j], 由于x在i左边,所以A[x]肯定能够率先扫描到Rmax[j].
然后,同时分别向左移动一位i和j,继续以上过程。因为我们已经确认存在j-1-i了,所以之后只需要考察j-i即可。
![](http://img.blog.csdn.net/20140102095145250?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdGVhc3ByaW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
图二,A[] = {1,0,0,0,2,1,1}
由于j首先到达右边边界,所以总的时间为O(n)。终于找到了线性查找的方法!一份实现代码如下:
小结:
1。二分查找的适用情况:待比较值m呈线性分布,并且存在一个极值(极大或极小)作为目标值。
2。对于存在两个变量的情况,如果希望实现时间为线性的查找,那么第一,看是否能够简化两个变量的关系,避免两变量相互独立;第二,当得到两变量某组合时,对数据的处理能否简化到时间O(1)。
注:题目来自leetcode, 同时也附有解法。不过网站在介绍O(n*lgn)的解法时用了排序,相比于我这里原创的方法二,既多用了空间,又多了一遍扫描,所以没有引用。网站介绍的O(n)的解法("Best Solution"),过于晦涩也没有完整代码,我从评论中找到一份实现,作为这里的方法三。
, 问找到最大的 j-i, 符合A[i] < A[j].
方法一:n个数据,两个变量,由于当i,j确定时,每次的比较很简单(A[i] ? A[j]),时间为O(1),所以最原始的暴力解法就是时间O(n^2)。
方法二:我们试着逐步降低时间复杂度。对于符合条件 A[i] < A[j]的 i 和 j,j-i 的可能取值范围为[1,n)。 由于必然存在一个极大值k = j-i, 当j-i > k时, 没有 j-i 符合条件;当j-i < k时,必有 j-i 符合条件(比如k序列的子序列)。所以k是在一个线性分布上的极大值,符合二分查找的应用条件。总的时间复杂度为O(n*lgn)
bool distanceExist(int *A, int n, int k, int& begin){ //k=j-i for(int i=0;i+k<n;++i){ if(A[i] < A[i+k]){ begin = i; return true; } } return false; } int maxDistance(int *A, int n, int& begin){ int u=n, v=0, m=0; while(v<u){ m = (u+v)/2; if(distanceExist(A, n, m, begin)){ v = m+1; //enlarge v to try greater m }else{ //reduce u to try smaller m u = m; } } return m; }方法三:我们来尝试一下是否存在时间O(n)的解法。考虑到题目中每一个元素A[i]和它右边的元素比较,如果强化一下,让A[i]和它右边所有元素中最大值比较,会有什么效果?
图一,A[] = {3,1,2,3,1,2,1}
如上图所示,我们有原始数组A[] = {3,1,2,3,1,2,1}, 纵坐标Rmax[i]表示的是从A[i]到最右边剩余数组中的最大值。如果我们从左边i=0开始,每次比较A[i] 和 Rmax[j] (i<j), 当A[i] < Rmax[j], 向右移动j, 当A[i] < Rmax[j] 刚刚不成立时,j-1-i即是A[0]到A[j]之间符合条件的最大j-i。因为如果有x<i, 能够符合A[x] < A[j], 由于x在i左边,所以A[x]肯定能够率先扫描到Rmax[j].
然后,同时分别向左移动一位i和j,继续以上过程。因为我们已经确认存在j-1-i了,所以之后只需要考察j-i即可。
图二,A[] = {1,0,0,0,2,1,1}
由于j首先到达右边边界,所以总的时间为O(n)。终于找到了线性查找的方法!一份实现代码如下:
int maxDistance_02(int *A, int n, int& left){ if(n<2) return 0; int *Rmax = new int (); Rmax[n-1] = A[n-1]; for(int i=n-2;i>=0;i--){ Rmax[i] = max(A[i], Rmax[i+1]); } int l=0, r=0, maxDiff=-1; while(l<n && r<n){ if(A[l] < Rmax[r]){ if(r-l > maxDiff){ maxDiff = r-l; left = l; } ++r; }else{ ++l; ++r; //resume to scan from the potential distance remaining r-l } } delete[] Rmax; return maxDiff; }
小结:
1。二分查找的适用情况:待比较值m呈线性分布,并且存在一个极值(极大或极小)作为目标值。
2。对于存在两个变量的情况,如果希望实现时间为线性的查找,那么第一,看是否能够简化两个变量的关系,避免两变量相互独立;第二,当得到两变量某组合时,对数据的处理能否简化到时间O(1)。
注:题目来自leetcode, 同时也附有解法。不过网站在介绍O(n*lgn)的解法时用了排序,相比于我这里原创的方法二,既多用了空间,又多了一遍扫描,所以没有引用。网站介绍的O(n)的解法("Best Solution"),过于晦涩也没有完整代码,我从评论中找到一份实现,作为这里的方法三。
相关文章推荐
- C++查找数组中的最大子数组
- 最大子数组问题---线性时间算法(转)
- 设计一个最优算法来查找n个元素数组中的最大值和最小值
- 【Core Java Volume 5】集合算法---查找数组、集合最大值的通用方法
- 最大子数组问题的递归和非递归(线性时间)代码
- ArrayTool是一个定义了操作数组常用的工具类,比如求最大值,排序,查找
- 算法导论第三版第四章 最大子数组和的三种解法(暴力、教材分治法、线性解法)
- java笔试题:数组查找,查找和为最大的子数组
- 给定数组,查找最小的k个元素或最大的k个元素
- 每日一题:查找数组中最大最小值
- 最大子数组和、最长递增子序列、最长公共子串、最长公共子序列、字符串编辑距离
- 查找数组中最大的两个数(Find two Largest Number)
- 【面试题-编程】查找数组中差值最大的两个数
- 算法导论第三版第四章 最大子数组和的三种解法(暴力、教材分治法、线性解法)
- 实验9(1)程序填空:下列程序在数组中同时查找最大元素和最小元素的下标,分别存放在 main()函数的max 和 min 变量中。要求:根据运行结果分析程序和填空,并注释说明填充依据。
- 每日一题:查找数组中最大最小值
- 分治法查找数组最大最小值
- javascript实现查找数组中最大值方法汇总
- C语言 查找数组中最大最小元素
- 数组字符串那些经典算法:最大子序列和,最长递增子序列,最长公共子串,最长公共子序列,字符串编辑距离,最长不重复子串,最长回文子串