题目:求一个旋转数组的最小数字


把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出旋转数组中的最小元素。例如, {1,2,3,4,5}的一个旋转数组为{3,4,5,1,2},该数组的最小元素为1.
旋转数组的特点:
(1)递增排序的数组旋转之后可以划分为两个排序的子数组;
(2)前面的子数组的元素都大于或等于后面子数组的元素;
(3)最小的元素刚好是这两个子数组的分界线;
(4)旋转数组在一定程度上是有序的;
这道题最直观的解法是从头到尾遍历一遍数组,就能找到最小的元素,这种思路的时间复杂度为O(n).在有序数组中利用二分查找法可以实现时间复杂度为O(logn)的查找。
算法分析:
1.设置两个指针i和j,初始状态i指向前面子数组的第一个元素,j指向后面子数组的后一个元素;
2. 找到找到i和j中间的元素middle,判断middle位于前面递增的子数组还是后面递增的子数组,若位于前面递增,则将i指向middle元素,此时最小元素应位于i和j之间;若middle位于后一个递增子数组,则将j指向middle元素,此时最小元素仍位于i和j之间;
3.循环步骤(1)(2),直到i和J之间没有中间元素为止;
4.此时j所指向的元素即为最小元素。
注意:当两个指针指向的数字及它们中间的数字三者相等时,无法判断中间数字位于前面的子数组还是后面的子数组,也就无法移动两个指针来缩小查找的范围,此时只能用顺序查找的方法。例如:数组{1,0,1,1,1}和数组{1,1,1,0,1}都可看成是递增数组{0,1,1,1,1}的旋转。第一种情况,中间数字位于后面的子数组,第二种情况,中间数字位于前面的子数组。
java代码实现:
/**************************************************************
* Copyright (c) 2016,
* All rights reserved.
* 版 本 号:v1.0
* 题目描述:求一个旋转数组的最小数字
* 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出旋转数组中的最小元素。例如,
* {1,2,3,4,5}的一个旋转数组为{3,4,5,1,2},该数组的最小元素为1.
* 输入描述:请输入一个旋转数组:
* 7 9 10 15 19 23 46 4 5
* 程序输出: 输入的旋转数组是:
* 7 9 10 15 19 23 46 4 5
* 最小数字是:4
* 问题分析:无
* 算法描述:旋转之后的数组实际上可以划分为两个排序数组,而且前面的子数组的元素都大于或等于后面子数组的元素。最小的数组刚好是两个子数组的分界线。
* (1)设两个指针i和j,分别指向头数组和尾数组
* (2)找到i和j中间的元素middle,判断middle位于前面递增的子数组还是后面递增的子数组,若位于前面递增,则将i指向middle元素,此时最小元素应位于i和j之间
* (3)若middle位于后一个递增子数组,则将j指向middle元素,此时最小元素仍位于i和j之间
* (4)循环步骤(1)(2),直到i和J之间没有中间元素为止
* (5)此时j所指向的元素即为最小元素。
* 完成日期:2016-07-24
***************************************************************/
package org.marsguo.offerproject;
import java.util.Scanner;
class FindMin{
/*输出用户输入的旋转数组*/
public FindMin(int[] s){
System.out.println("输入的旋转数组为:");
for(int i = 0; i < s.length; i++){
System.out.print(s[i] + " ");
}
System.out.println();
}
/*寻找最小元素方法*/
public void searchfun(int[] array){
int i = 0; //将i指向数组的头
int j = array.length-1; //将j指向数组尾
int middle = array.length/2; //找到中间的那个元素
//System.out.println("中间数字为:" + array[middle]);
while(i<j){ //当i<j时一直循环寻找
if(array[middle]>array[i]){ //判断中间元素是否大于头元素
i = middle; //将i指向中间元素
}else if(array[middle]<array[j]){ //判断中间元素是否小于尾元素
j =middle; //将j指向尾元素
}
middle = (j-i)/2 + i; //重新寻找新i和j中间的元素
//System.out.println("中间数字为" + array[middle]);
if(middle == i){ //如果此时中间元素即为i,证明已经全部找完
System.out.println("最小的数字是:" + array[j]); //输出最小元素,此时最小元素即为j所指向的元素
break; //退出整个循环,结束程序。
}
}
}
}
public class SearchMin {
public static void main(String args[]){
Scanner scanner = new Scanner(System.in); //扫描键盘输入
System.out.println("请输入一个旋转数组:");
String str = scanner.nextLine(); //将键盘输入转化为字符串
String[] temp = str.split(" "); //将字符串用“ ”分开转化为字符串数组
int[] array = new int[temp.length]; //定义一个整型数组array
for(int i = 0; i< temp.length; i++){ //将字符串数组强制转化为整型数组
array[i] = Integer.parseInt(temp[i]); //这种方法非常巧妙
}
FindMin findmin = new FindMin(array); //创建对象
findmin.searchfun(array); //调用对象寻找最小元素方法
}
}
程序输出: