zoukankan      html  css  js  c++  java
  • [剑指Offer]11-旋转数组的最小数字(二分)

    题目链接

    https://www.nowcoder.com/practice/9f3231a991af4f55b95579b44b7a01ba?tpId=13&tqId=11159&tPage=1&rp=4&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking

    题意

    把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。 输入一个非减排序的数组的一个旋转,输出旋转数组的最小元素。 例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。 NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。

    解题思路

    使用二分查找思想,可以将时间复杂度由O(n)优化到O(logn)。
    旋转数组特点:

    • 由左右两个有序数组组成,左边的数组元素都大于等于右边的数组元素,要找的最小元素是右边数组的第一个。
    • 可以采用二分法,拿中间元素与左右两端元素比较,若大于等于l,则中间元素属于左数组,令l=mid;若小于等于r,则中间元素属于右数组,令r=mid。
    • 最终,将l=r-1,而最小元素即为r所指元素,这是终止条件。

    二刷解题思路更新

    • 还是用原始二分的初始化l=0;r=arr.length-1;
    • 但是while条件是l<r-1保证l=r-1是结束,返回r即可。此外,mid=r;mid=l。保证l一直在左区间,r一直在右区间。

    考虑特例:

    • 特例1 左旋转为前0个,此时最小元素为第一个,要单独判断这种情况。
    • 特例2 l r mid 三个指向的元素相同,此时无法判断mid要归在左边还是右边,进而影响最终的结果,所以这种情况只能使用顺序查找。

    相关知识

    二分查找的思考:

    • 二分查找方法的关键是用数组中间的元素与某些东西比较,达到每次减少一半范围的效果,以将查找复杂度优化到O(logn)。
    • 大部分题目使用二分是在“有序”的情景下,但是无序也可以使用二分,只要能确定二分的某一侧肯定有要找的内容即可。

    代码(C++)

    class Solution {
    public:
    	int minNumberInRotateArray(vector<int> rotateArray) {
    		if (rotateArray.size() == 0) {
    			return 0;
    		}
    		else if (rotateArray.size() == 1) {
    			return rotateArray[0];
    		}
    		else{
    			size_t l = 0;
    			size_t r = rotateArray.size() - 1;
    
    			if (rotateArray[l] < rotateArray[r]) {//特例1 旋转左边0个
    				return rotateArray[l];
    			}
    
    			size_t mid;
    			while (l != r - 1) {
    				mid = (l + r) / 2;
    				if (rotateArray[l] == rotateArray[r] && mid == rotateArray[l]) {//特例2 三者相等,无法判断mid指向的元素属于左边的有序数组还是右边的有序数组,此时只能采用顺序查找
    					break;
    				}
    				if (rotateArray[mid] >= rotateArray[l]) {
    					l = mid;
    				}
    				else if (rotateArray[mid] <= rotateArray[r]) {
    					r = mid;
    				}
    			}
    
    			if (l != r - 1) {//顺序查找
    				int min = rotateArray[0];
    				for (int i = 1;i < rotateArray.size();++i) {
    					if (rotateArray[i] < min) {
    						min = rotateArray[i];
    					}
    				}
    				return min;
    			}
    			else {
    				return rotateArray[r];
    			}
    		}
    	}
    };
    

    代码(Java)

    public class Solution {
    	public int minNumberInRotateArray(int[] array) {
    		if (array.length == 0) {
    			return 0;
    		} else if (array.length == 1) {
    			return array[0];
    		} else {
    			int l = 0;
    			int r = array.length - 1;
    
    			if (array[l] < array[r]) {// 旋转0
    				return array[l];
    			}
    
    			while (l < r - 1) {
    				int mid = (l + r) >> 1;
    				if (array[l] == array[mid] && array[mid] == array[r]) {
    					break;
    				}
    				if (array[mid] >= array[l]) {
    					l = mid;
    				}
    				else if (array[mid] <= array[r]) {
    					r = mid;
    				}
    			}
    
    			int min;
    			if (l != r - 1) {// 使用循环查找
    				min = Integer.MAX_VALUE;
    				for (int i = 0; i < array.length; ++i) {
    					if (array[i] < min) {
    						min = array[i];
    					}
    				}
    			} else {
    				min = array[r];
    			}
    			return min;
    		}
    	}
    
  • 相关阅读:
    Fast polling using C, memcached, nginx and libevent
    为什么MongoDB可以替代MySQL?
    comet server 的介绍及方案选型
    多任务服务器架构设计
    基于libev面向分布式数据系统的C10K服务器设计
    libev & libevent简介
    memcached、redis、mysql、mongodb结合架构数据库系统
    删除数组中的重复元素
    不用运算符比较两个int数的大小
    JDBC之简介
  • 原文地址:https://www.cnblogs.com/coding-gaga/p/10473889.html
Copyright © 2011-2022 走看看