Find Minimum in Rotated Sorted Array 典型二分查找
https://oj.leetcode.com/problems/find-minimum-in-rotated-sorted-array/
Suppose a sorted array is rotated at some pivot unknown to you beforehand.
(i.e., 0 1 2 4 5 6 7
might become 4 5 6 7 0 1 2
).
Find the minimum element.
You may assume no duplicate exists in the array.
解题思路:
最朴素的O(n)的方法,就是找到突然变小的那个元素,肯定是最小的。否则就说明所有元素一直变大,本来就是排序的,则返回第一个元素。
public class Solution {
public int findMin(int[] num) {
if(num.length == 0){
return 0;
} int min = num[0]; for(int i = 0; i < num.length; i++){
if(num[i] < min){
return num[i];
}
}
return min;
}
}
不过本题还有一个二分查找的方法,可以将时间复杂度降为O(lgN)。代码如下。
public class Solution {
public int findMin(int[] num) {
if(num.length == 0){
return 0;
} if(num.length == 1){
return num[0];
} int start = 0;
int end = num.length - 1;
int min = Integer.MAX_VALUE; if(num[start] < num[end]){
return num[start];
} while(start <= end){
if(start == end){
return Math.min(min, num[start]);
}
int mid = (start + end) / 2; if(num[start] <= num[mid]){
min = Math.min(min, num[start]);
start = mid + 1;
}else{
min = Math.min(min, num[mid]);
end = mid - 1;
}
}
return min;
}
}
二分查找是一个很简单,却很难完全写对的算法,编程珠玑里写道,差不多只有10%的程序员能正确的实现它。问题主要处在边界变量的定义,和循环条件的定义上。让我们从程序的开头看起。
将end定义为length - 1,就意味着这是一个[0, length - 1]的左右都闭合的区间,所以循环的条件一定是start <= end。所以再到循环内部,start = mid + 1, end = mid - 1,都是因为这是一个闭合的区间,这样做才不会漏元素。
如果end定义为length,那么就意味着这个区间是左闭合有开的,[0, length)。所以后面while的条件就变为start < end,循环内部,start = mid + 1, end = mid。
这样理解起来就不会出错。其实这就是循环不变式的概念,loop invariant。可以参考下面的页面,对于这个比较基础的知识介绍的很好。
http://www.cppblog.com/converse/archive/2009/09/21/96893.aspx
update: 2015/03/11
下面一段我写的,更为简洁的代码。看几个例子,7 8 0 1 2 3 4 5 6,mid=2;3 4 5 6 7 8 0 1 2,mid=7。
mid > end的时候,代表前面是排序的,可能折断点在后面,于是start=mid+1。
mid < end的时候,代表后面是排序的,可能折断点在前面,但是这时候不能end = mid - 1。为什么?看一个例子,4 5 0 1 2。这时mid < end,但是mid就是折断点,所以这时end = mid。
mid == end的时候,说明当前mid就是最小值。
为什么mid要和end比较,不能和start?因为除非在start==end的情况,否则mid不可能等于end,但是start可能等于mid,比如只有两个元素,[2,1],这时start==mid<end,所以返回的是错误的2。
另外还要注意一点。while内部更新start和end的各个条件要符合互相没有交集,但是合起来又可以组成全集的原理。因为前半句违背了,可能一次更新多次start和end,这样有些范围就跳过不搜索了。后半句违背了,可能使得start和end得不到更新,引起死循环。
这个性质其实也和上面说的循环不变式同理,需要体会。
public class Solution {
public int findMin(int[] num) {
int start = 0;
int end = num.length - 1;
while(start <= end){
int mid = (start + end) / 2;
if(num[end] == num[mid]){
return num[mid];
}
if(num[end] < num[mid]){
start = mid + 1;
}
if(num[end] > num[mid]){
end = mid;
}
}
return -1;
}
}
二分查找的题目很多,基本原理就是这样,但是具体情况,mid的值和哪个值比较,状态变化和终止的条件,变化万千,需要细细体会。
这道题是二分查找里比较经典的题目,也比较灵活,相应条件的定义和start、end的转换可以有多种写法。
Find Minimum in Rotated Sorted Array 典型二分查找的更多相关文章
- Search in Rotated Sorted Array(二分查找)
Suppose a sorted array is rotated at some pivot unknown to you beforehand. (i.e., 0 1 2 4 5 6 7 migh ...
- Find Minimum in Rotated Sorted Array I&&II——二分查找的变形
Find Minimum in Rotated Sorted Array I Suppose a sorted array is rotated at some pivot unknown to yo ...
- [LeetCode] Find Minimum in Rotated Sorted Array II 寻找旋转有序数组的最小值之二
Follow up for "Find Minimum in Rotated Sorted Array":What if duplicates are allowed? Would ...
- [LeetCode] Find Minimum in Rotated Sorted Array 寻找旋转有序数组的最小值
Suppose a sorted array is rotated at some pivot unknown to you beforehand. (i.e., 0 1 2 4 5 6 7 migh ...
- 【leetcode】Find Minimum in Rotated Sorted Array I&&II
题目概述: Suppose a sorted array is rotated at some pivot unknown to you beforehand.(i.e., 0 1 2 4 5 6 7 ...
- Leetcode | Find Minimum in Rotated Sorted Array I && II
Suppose a sorted array is rotated at some pivot unknown to you beforehand. (i.e., 0 1 2 4 5 6 7 migh ...
- 简单的算法题, Find Minimum in Rotated Sorted Array 的Python实现。
简单的算法题, Find Minimum in Rotated Sorted Array 的Python实现. 题目: Suppose a sorted array is rotated at som ...
- [OJ] Find Minimum in Rotated Sorted Array II
LintCode 160. Find Minimum in Rotated Sorted Array II (Medium) LeetCode 154. Find Minimum in Rotated ...
- LeetCode OJ 154. Find Minimum in Rotated Sorted Array II
Follow up for "Find Minimum in Rotated Sorted Array":What if duplicates are allowed? Would ...
随机推荐
- 12--C++_运算符重载
C++_运算符重载 什么是运算符的重载? 运算符与类结合,产生新的含义. 为什么要引入运算符重载? 作用:为了实现类的多态性(多态是指一个函数名有多种含义) 怎么实现运算符的重载? 方式:类的成员函数 ...
- wpf绑定静态变量,模拟rem单位
using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; usin ...
- Centos7搭建ansible运维自动化工具
1)设置主机名和hosts文件 2)配置阿里云repo源 Wget -O /etc/yum.repos.d/aliyun.repo https://mirrors.aliyun.com/repo/Ce ...
- Python学习【第5篇】:Python之函数(自定义函数,内置函数,装饰器,迭代器,生成器、模块)
一.为什么要使用函数? 1.避免代码重用 2.提高代码的可读性 二.函数的定义与调用 1. def 函数名(参数1,参数2): ''' 函数注释''' print('函数体') return 返回值 ...
- ES6学习历程(变量的声明)
2019-01-25: 一:变量的声明: 1.对于变量的声明添加了let,const两种方式 关于let: (1)不存在变量提升--必须先声明再使用; (2)会出现暂时性死区--在一个方法外用var声 ...
- for循环提高内存访问效率的做法
今天写程序的时候突然想到一点,记录一下: 计算机内存地址是线性排列组织的,而利用for循环对高维数组结构进行遍历处理的时候,要保证最内层for循环遍历的是高维数组的最低维度,这样可以最大化利用CPU的 ...
- UID中RUID、EUID和SUID的区别
看UNIX相关的书时经常能遇到这几个概念,但一直没有好好去理清这几个概念,以致对这几个概念一直一知半解.今天好好区分了一下这几个概念并总结如下.说白了这几个UID引出都是为了系统的权限管理. 下面分别 ...
- C++编写谷歌日历
#include<iostream> #include<fstream> using namespace std; void main() //程序从这里开始运行 { int ...
- 发现:Click事件也能获取鼠标单击的坐标
按照MSDN的说明以及平时的习惯,我们要获取鼠标单击时的相对坐标,都会使用MouseClick等事件,今天,偶然发现,原来Click事件也可以. /* 惊天地泣鬼神的考古业绩. * 原来Cilck事件 ...
- node.js 中的package.json文件怎么创建?
最近在用webstorm和nodejs做一些东西,老是各种混乱,今天上午创建一个新的项目,结果发现,npm init之后,并没有出现package.json,并没有太明确他的功能的小姑娘表示十分的惊慌 ...