剑指Offer面试题(第八天)面试题11(1)、11(2)

 * 快速排序:


     * 算法思想:基于分治的思想,是冒泡排序的改进型。
     * 首先在数组中找到一个基准点(基准点的选择可能会影响快速排序的效率,在补充处)
     * 然后分别从数组的两端扫描数组,设两个指标(lo指向起始位置,hi指向末尾),
     * 首先从后半部分开始,若果发现有比基准点小的,就交换lo和hi的值,
     * 然后再从前半段开始扫描,发现有比基准点大的,就交换lo和hi的值,
     * 如此往复循环,直到lo>=hi,然后把基准点的值放到hi这个位置
     * 一次排序就完成了
     * 接下来采用递归的方式分别对前半部分和后半部分排序,当前半部分有序、后半段有序,整个数组就自然有序列
     * 快速排序的时间复杂度是O(NlogN)
     * 
     * 【补充】:基准点的选取
     * https://www.cnblogs.com/y3w3l/p/6444837.html
     * https://blog.csdn.net/liuyi1207164339/article/details/50827608
    

package Test;

import java.util.ArrayList;
import java.util.Scanner;

public class No11_quickSort {

	/*
	 * 快速排序:
	 * 算法思想:基于分治的思想,是冒泡排序的改进型。
	 * 首先在数组中找到一个基准点(基准点的选择可能会影响快速排序的效率,在补充处)
	 * 然后分别从数组的两端扫描数组,设两个指标(lo指向起始位置,hi指向末尾),
	 * 首先从后半部分开始,若果发现有比基准点小的,就交换lo和hi的值,
	 * 然后再从前半段开始扫描,发现有比基准点大的,就交换lo和hi的值,
	 * 如此往复循环,直到lo>=hi,然后把基准点的值放到hi这个位置
	 * 一次排序就完成了
	 * 接下来采用递归的方式分别对前半部分和后半部分排序,当前半部分有序、后半段有序,整个数组就自然有序列
	 * 快速排序的时间复杂度是O(NlogN)
	 * 
	 * 【补充】:基准点的选取
	 * https://www.cnblogs.com/y3w3l/p/6444837.html
	 * https://blog.csdn.net/liuyi1207164339/article/details/50827608
	 * 
	 * 
	 * */
	static int[] array = new int[8];
	public static void main(String[] args) {
		// TODO Auto-generated method stub
 
		
		Scanner in = new Scanner(System.in);
		System.out.println("请向数组输入8个整数:");
		for(int i=0;i<8;i++) {
			array[i] = in.nextInt();
		}
		
		System.out.println("输出快速排序的结果:");
		sort(array,0,7);
		for(int i=0;i<8;i++) {
			System.out.println(array[i]+" ");
			
			
		}
		
		
	}
	
	public static int partition(int[] array,int lo,int hi) {
		
		if(lo>=hi) {
			return -1;
		}
		//基准数选取为lo位置,固定的切分方式
		int key = array[lo];
		
		while(lo<hi) {
			while(array[hi]>=key&&lo<hi) {
				hi--;
			}
			//将hi的值付给了lo  造成了hi为空(并非真的没有值,而是没有再进行赋值的意思)
			array[lo]=array[hi];  
			while(array[lo]<=key&&lo<hi) {
				lo++;
			}
			//将lo的值赋给hi  造成了lo为空
			array[hi]=array[lo];
			
		}
		array[hi] = key;  //此时hi = lo,所以赋给hi或者lo都可以
		return hi;        
		
		
	}
	
	public static void sort(int[] array,int lo,int hi) {
		if(lo>=hi) {
			return;
		}
		int index = partition(array,lo,hi);
		sort(array,lo,index-1);
		sort(array,index+1,hi);
		
	}
	
	
	

}

 * 面试题11:旋转数组的最小数字


     * 题目:把一个数组最开的的若干个元素搬到数组的末尾,我们称之为数组的旋转。
     * 输入一个递增排序的数组的一个旋转,输出旋转数组的 最小元素。
     * 例如:数组{3,4,5,1,2}为{1,2,3,4,5}的一个选装,该数组的最小值为1.
     * 
     * 
     * 思路:利用二分法,设置两个指针,第一个变量指向第一个元素,第二个变量指向最后一个元素
     *         找到中间的数,首先和第一个变量进行对比,若是比第一个变量大,则中间元素属于前半部分数组,将第一个元素的指向移到中间位置
     *                     然后和第二个变量进行对比,若是比第二个变量小,则中间元素属于后半部分数组,将第二个元素的指向移到中间位置
     *         查找范围缩小一半,再进行新一轮的查找。。。
     *         直到第一个指向前半部分数组的最后一个,第二个指向后半数组的第一个,也就是两者相邻
     *         第二个指向的就是最小的元素
     * 
     *         其中根据旋转数组的定义还有一个特例,也就是将排序数组的前面0个元素搬到最后去,
     *         也就是排序数组本身,这仍然是数组的一个旋转,也就是第一个数字大于最后一个数字时,直接返回第一个数字就可
     *         若是左中右三值相等时,又该如何呢,前面的思路不能支持这种情况,
     *         所以原来的方法不可行,
     *         例如:1,0,1,1,1与1,1,1,0,1情况
     *         这里我们采用顺序查找的方式进行  其他还有不是用这种解决的   

               详见https://blog.csdn.net/baiye_xing/article/details/78428318     中的第8个

package Test;

import java.util.Scanner;

public class No11min {

	/*
	 * 面试题11:旋转数组的最小数字
	 * 题目:把一个数组最开的的若干个元素搬到数组的末尾,我们称之为数组的旋转。
	 * 输入一个递增排序的数组的一个旋转,输出旋转数组的 最小元素。
	 * 例如:数组{3,4,5,1,2}为{1,2,3,4,5}的一个选装,该数组的最小值为1.
	 * 
	 * 
	 * 思路:利用二分法,设置两个指针,第一个变量指向第一个元素,第二个变量指向最后一个元素
	 * 		找到中间的数,首先和第一个变量进行对比,若是比第一个变量大,则中间元素属于前半部分数组,将第一个元素的指向移到中间位置
	 * 				    然后和第二个变量进行对比,若是比第二个变量小,则中间元素属于后半部分数组,将第二个元素的指向移到中间位置
	 * 		查找范围缩小一半,再进行新一轮的查找。。。
	 * 		直到第一个指向前半部分数组的最后一个,第二个指向后半数组的第一个,也就是两者相邻
	 * 		第二个指向的就是最小的元素
	 * 
	 * 		其中根据旋转数组的定义还有一个特例,也就是将排序数组的前面0个元素搬到最后去,
	 * 		也就是排序数组本身,这仍然是数组的一个旋转,也就是第一个数字大于最后一个数字时,直接返回第一个数字就可
	 * 		若是左中右三值相等时,又该如何呢,前面的思路不能支持这种情况,
	 * 		所以原来的方法不可行,
	 * 		例如:1,0,1,1,1与1,1,1,0,1情况
	 * 		这里我们采用顺序查找的方式进行
	 * 
	 * 
	 * */
	public static void main(String[] args) {
		// TODO Auto-generated method stub

		int[] array = new int[5];
		Scanner in = new Scanner(System.in);
		System.out.println("输如一个长度为5的数组:");
		for(int i=0;i<5;i++) {
			array[i]=in.nextInt();
		}
		System.out.println("利用旋转数组的特性,输出数组中最小的元素"+min(array));
		
	}

	private static int min(int[] array) {
		// TODO Auto-generated method stub
		if(array==null||array.length==0) {
			return 0;	
		}
		

		
		int left = 0;
		int right =array.length-1;
		//若是旋转0位,则将array[0]的值返回即可
		int min = array[left];
		
		while(array[left] >= array[right]) {
			
			if(right-left<=1) {
				min = array[right];
				break;
			}
			
			int mid = (left+right)/2;
			
			if(array[mid]==array[left]&&array[mid]==array[right]) {
				min = minInOrder(array,left,right);
				break;
			}
			else if(array[mid]>=array[left]) {
				left = mid;
			}
			else if(array[mid]<=array[right]) {
				right = mid;
			}	
			
		}
			
		return min;
	}

	private static int minInOrder(int[] array, int left, int right) {
		// TODO Auto-generated method stub
		int result = array[left];
		
		for(int i=left+1;i<=right;i++) {
			if(result > array[i]) {
				result = array[i];
			}
		}
		return result;
	}

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值