单调旋转数组的TopK问题
问题描述:输入一个单调旋转后的数组,求该数组中的第k小的元素。
分析:很多人看到这个题目会有点懵,可能读者不知道什么是旋转数组,我先解释下两个概念,
旋转数组的定义:把一个数组的前几项元素移动到数组的末尾,称之为数组的旋转。
单调旋转数组的定义:如果数组在旋转之前是一个单调数组,则旋转之后称之为单调旋转数组。
为了方便解释,这里我以单调非递减的旋转数组为例进行解释,其他类型可以通过这个例子类推。
解法一:最简单的方法就是从头到位扫描一遍,求出小的元素下标,进而推算出第k小的元素下标,即可得到答案。
但是这样做的时间复杂度为O(n).还可以寻求更快的解法。
解法二:充分利用数组的单调性质解题,可以发现旋转之后的数组可以划分为两个单调子数组,其中一个单调子数组所有的元素都大于等于另一个数组中的元素。
并且最小的元素正好是两个元素的分解点,这样就可以使用二分查找法进行查找。
可以设置三个指针left,right,mid分别指向数组头元素、尾元素和中间元素的下标。利用中间元素去和头元素比较,有两种情况:
如果a[mid]>=a[left],则令left=mid
如果a[mid]<a[left],则令right=mid
然后再重新计算mid,就这样一直循环去做,直到left+1==right停止,此时rigth就是最小元素下标,再根据k计算出第k小元素的下标即可。
此方法的时间复杂度为O(logn)。
对比:很明显解法二比解法一要快,但是要求数组必须是单调数组,而解法一可以用于所有的旋转数组。由于解法一,比较简单,我就不再编程实现了,我主要对解法二去编程实现。
对于一般的测试样例,解法二都没问题,但是对于特殊的测试样例,却出现了问题。
例如:1,0,1,1,1和1,1,1,0,1可以发现结果不正确,因此需要加以改进,如果left,right,mid所指元素都相等,解法二无能为力,需要使用解法一求解。
我们可以在程序中对待这一特定条件去单独判断即可。
另外解法二还可以进一步优化,如果a[left]<a[right],我们直接就可以求出a[left]就是最小的元素,进而根据k求出第k小的元素。
具体的Java代码如下,代码写法都比较通用,读者可以很容易的转化为其他语言实现。
 public class Main{
     public static void mintopk(int a[],int k){
         if(a==null ||k<=0 ||k>a.length)                      //如果数组不存在或者k不符合要求,则直接结束
             { System.out.println("不存在");
               return ;
             }
         int p;                                              //用来表示mintopk数的下标
         int left=0,right=a.length-1,mid=(left+right)/2;     //求出起初的开始、结束和中间元素下标
         if(a[mid]==a[left] && a[mid]==a[right])             //如果三个下标所指元素相等,则从头开始扫描
             for(int i=1;i<a.length;i++)
                 if(a[i-1]>a[i])
                 {   p=i+k-1;
                     if(p>a.length-1)p=p-a.length;           //求出mintopk的下标
                     System.out.println(a[p]);
                     return;
                 }
         if(a[left]<a[right])                                //如果头元素小于尾元素,则表明left所指为最小元素
         {
             p=left+k-1;
             if(p>a.length-1)p=p-a.length;
             System.out.println(a[p]);
             return;
         }
         while((left+1)!=right)                              //利用三个指针进行查找
         {
             if(a[mid]>=a[left])left=mid;
             else right=mid;
             mid=(left+right)/2;
         }
         p=right+k-1;
         if(p>a.length-1)p=p-a.length;
         System.out.println(a[p]);
     }
     public static void main(String[] args) {
         // TODO 自动生成的方法存根
         int a[]={3,4,5,1,2};
         int k=5;
         mintopk(a,k);
     }
 }
输出结果为:
5
注意:代码中我只写了一组测试例子,读者可以下载代码自行验证。
单调旋转数组的TopK问题的更多相关文章
- 剑指Offer面试题:7.旋转数组的最小数字
		一.题目:旋转数组的最小数字 题目:把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转.输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素.例如数组{3,4,5,1,2}为{1,2 ... 
- P66、面试题8:旋转数组的最小数字
		题目:把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转.输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素.例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数 ... 
- 《剑指offer》第十一题(旋转数组的最小数字)
		// 面试题:旋转数组的最小数字 // 题目:把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转. // 输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素.例如数组 // {3, ... 
- 旋转数组的最小数字(C++ 和 Python 实现)
		(说明:本博客中的题目.题目详细说明及参考代码均摘自 “何海涛<剑指Offer:名企面试官精讲典型编程题>2012年”) 题目 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的 ... 
- 剑指offer——面试题11:旋转数组的最小数字
		#include"iostream" using namespace std; int GetMinNumber(int *data,int len) { ,right=len-, ... 
- 剑指Offer的学习笔记(C#篇)-- 旋转数组的最小数字
		题目描述 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转. 输入一个非减排序的数组的一个旋转,输出旋转数组的最小元素. 例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋 ... 
- [LeetCode] Rotate Array 旋转数组
		Rotate an array of n elements to the right by k steps. For example, with n = 7 and k = 3, the array ... 
- 剑指Offer 旋转数组的最小数字
		题目描述 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转.输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素.例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转 ... 
- 42.旋转数组的最小元素[Get min value of rotated array]
		[题目] 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转.输入一个排好序的数组的一个旋转,输出旋转数组的最小元素.例如数组{3, 4, 5, 1, 2}为{1, 2, 3, 4, 5 ... 
随机推荐
- hdu 3478 Catch(染色  dfs 或 bfs )
			Problem Description A thief is running away! We can consider the city to N–. The tricky thief starts ... 
- Spting使用memcached
			applicationContext.xml配置文件: <?xml version="1.0" encoding="UTF-8"?> <bea ... 
- oracle Recyclebin
			每个用户都有自己的Recycle Bin.删除的对象不会永久存储在Recycle Bin中,Oracle会按照一定的规则自动清除里面的内容,如没有足够的空间.执行show recyclebin时只列出 ... 
- [AC自动机][HDU3065]
			//====================== // HDU 2222 // 求目标串中出现了几个模式串 //输入 //1 //5 //she //he //say //shr //her //ya ... 
- 通过匹配绑定select option的文本值 模糊匹配
			//通过匹配绑定select option的文本值 模糊匹配 $(".class option:contains('文本值')").attr("selected" ... 
- 转JS技巧
			前端已经被玩儿坏了!像console.log()可以向控制台输出图片等炫酷的玩意已经不是什么新闻了,像用||操作符给变量赋默认值也是人尽皆知的旧闻了,今天看到Quora上一个帖子,瞬间又GET了好多前 ... 
- 搭建discuz论坛(2)
			修改host文件: 使用ab做性能测试: E:\Apache2.2\bin>ab -n1000 -c100 http://bbs.ct.gd/ 
- vector 汇总
			Vector成员函数 函数 表述 c.assign(beg,end) c.assign(n,elem) 将[beg; end)区间中的数据赋值给c. 将n个elem的拷贝赋值给c. c.at(idx) ... 
- How can I get the logical valume by the datafile names and ASM disks?
			Q:We use asmlib to create ASM disk in Oracle rac 11.2.0.3, and how can I get the logical valume by t ... 
- Hibernate注解学习1
			由于项目的原因目前需要一些简单注解,于是就做了个hibernate注解的小demo,来记录一下. 1.需要引入jar包ejb3-persistence.jarhibernate-annotations ... 
