问题描述:输入一个单调旋转后的数组,求该数组中的第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问题的更多相关文章

  1. 剑指Offer面试题:7.旋转数组的最小数字

    一.题目:旋转数组的最小数字 题目:把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转.输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素.例如数组{3,4,5,1,2}为{1,2 ...

  2. P66、面试题8:旋转数组的最小数字

    题目:把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转.输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素.例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数 ...

  3. 《剑指offer》第十一题(旋转数组的最小数字)

    // 面试题:旋转数组的最小数字 // 题目:把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转. // 输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素.例如数组 // {3, ...

  4. 旋转数组的最小数字(C++ 和 Python 实现)

    (说明:本博客中的题目.题目详细说明及参考代码均摘自 “何海涛<剑指Offer:名企面试官精讲典型编程题>2012年”) 题目 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的 ...

  5. 剑指offer——面试题11:旋转数组的最小数字

    #include"iostream" using namespace std; int GetMinNumber(int *data,int len) { ,right=len-, ...

  6. 剑指Offer的学习笔记(C#篇)-- 旋转数组的最小数字

    题目描述 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转. 输入一个非减排序的数组的一个旋转,输出旋转数组的最小元素. 例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋 ...

  7. [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  ...

  8. 剑指Offer 旋转数组的最小数字

    题目描述 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转.输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素.例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转 ...

  9. 42.旋转数组的最小元素[Get min value of rotated array]

    [题目] 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转.输入一个排好序的数组的一个旋转,输出旋转数组的最小元素.例如数组{3, 4, 5, 1, 2}为{1, 2, 3, 4, 5 ...

随机推荐

  1. hdu 4751 Divide Groups(dfs染色 或 2-sat)

    Problem Description   This year is the 60th anniversary of NJUST, and to make the celebration more c ...

  2. HTTP学习笔记

    最近在看HTTP权威指南, 然后准备从Python的request库入手,看它的源代码实现 http://cn.python-requests.org/zh_CN/latest/ 挖坑 今年准备在gi ...

  3. Ffmpeg和SDL如何同步视频(转)

    ong> PTS和DTS 幸运的是,音频和视频流都有一些关于以多快速度和什么时间来播放它们的信息在里面.音频流有采样,视频流有每秒的帧率.然而,如果我们只是简单的通过数帧和乘以帧率的方式来同步视 ...

  4. Base64编码和解码算法

    Base64么新鲜的算法了.只是假设你没从事过页面开发(或者说动态页面开发.尤其是邮箱服务),你都不怎么了解过,仅仅是听起来非常熟悉. 对于黑客来说,Base64与MD5算法有着相同的位置.由于电子邮 ...

  5. ARCGIS接口详细说明

    ArcGIS接口详细说明 目录 ArcGIS接口详细说明... 1 1.      IField接口(esriGeoDatabase)... 2 2.      IFieldEdit接口(esriGe ...

  6. ASP.NET MVC中移除冗余Response Header

    本文主要介绍如何优化ASP.NET MVC使用IIS时Response Header中的不必要的信息 默认的,创建一个ASP.NET MVC项目,会在Response Header中包含一些敏感的信息 ...

  7. servlet 之 返回json数据并显示

    //实体类import java.util.ArrayList; public class ObjectType { private String type; private ArrayList< ...

  8. xaml控件样式大全(太有用了)C#

    地址:链接:http://pan.baidu.com/s/1jGlMyEi 密码:zaeg http://blog.csdn.net/lhx527099095/article/category/943 ...

  9. rowid的作用

    一.快速删除重复的记录的方法: 1.通过创建临时表删除重复的的记录 1)创建emp表的临时表,把数据导入临时表中,删除原来的表中的数据然后把临时表中的数据导入原表 create table emp_t ...

  10. 【搜索引擎Jediael开发笔记2】使用HttpClient下载网页至本地文件

    本文使用HttpClient根据url进行网页下载.其中 (1)HttpClient的相关知识请参见HttpClient基础教程 (2) package org.ljh.search.download ...