整体思路
分支步骤:分解问题
(1)分解:将原问题分解成一系列子问题
(2)解决:递归地解各子问题。若子问题足够小,则直接有解;
(3)合并:将子问题的结果合并成原问题的解
题目
1、快速排序
(1)题目
就是数组的快速排序啦
(2)代码
package com.lanqiao.vidio;
public class QuickSort {
public static void main(String[] args) {
int[] A = {9,6,1,5,8};
sort(A,0,A.length-1);
for(int a:A)
{
System.out.print(a+" ");
}
}
public static void sort(int[] A,int p,int r)
{
if(p<r)
{
int q=partition(A,p,r);
sort(A,p,q-1);
sort(A,q+1,r);
}
}
private static int partition(int[] A, int p, int r) {
int pivot = A[p];
int sp = p+1;
int bigger = r;
while(sp<=bigger)
{
if(A[sp]<=pivot)
{
sp++;
}else {
int temp = A[sp];
A[sp]=A[bigger];
A[bigger]=temp;
bigger--;
}
}
int temp = A[p];
A[p]= A[bigger];
A[bigger]=temp;
return bigger;
}
}
(3)思路
(1)分治法思想
(2)选一个枢轴,找到其相应位置
(3)枢轴左侧有序
(4)枢轴右侧有序
(5)整体有序
(4)找枢轴注意点
(1)确定左右指针sp和bigger,如果sp<pivote,指针前进,否则,bigger与sp元素交换,bigger前进直到sp>bigger比较完成
(2)交换完成后,即找到了枢轴一个在的位置,bigger,右侧都比枢轴元素小,右侧都比枢轴元素大
(3)bigger是当前枢轴所在,返回bigger,,进行左侧进行排序,找枢轴,左侧枢轴定位,右侧排序,直到最终全部有序。
2、双向扫描 快排
1、代码:
package com.lanqiao.vidio;
public class QuickSort1 {
public static void main(String[] args) {
int[] A = {9,5,8,1,6};
sort(A,0,A.length-1);
for(int a:A)
{
System.out.print(a+" ");
}
}
private static void sort(int[] A, int i, int j) {
if(i<j) {
int p = petition(A,i,j);
sort(A,i,p-1);
sort(A,p+1,j);
}
}
private static int petition(int[] A, int i, int j) {
int pivot = A[i];
int left = i+1;
int right = j;
while(left<=right)
{
while(left<=right&&A[left]<=pivot) left++;//找到左侧第一个比pivot大的数
while(left<=right&&A[right]>pivot) right--;//找到右侧第一个小于等于pivot的数
if(left<right)
{
int temp = A[left];
A[left]=A[right];
A[right]=temp;
}
}
int temp = A[i];
A[i]=A[right];
A[right]=temp;
return right;
}
}
2、注意点:
(1)在进入枢轴选择方法之前,先判断i和j的关系,否则可能j已经<0了仍然判断,导致越界。
(2)pivot选择优化:选择最大值+最小值/2
3、奇数偶数分离(奇数在前、偶数在后)
1、题目
将一个数组中所有元素进行分离,使得奇数在前,偶数在后,不必关心大小顺序
2、代码
package com.lanqiao.vidio;
public class jiou {
public static void main(String[] args) {
int[] arr = {1,4,2,3,5,8,7};
merge(arr,0,arr.length-1);
for(int a:arr)
{
System.out.print(a+" ");
}
}
private static void merge(int[] arr, int i, int j) {
int left = i;
int right = j;
while(left<right)
{
while(left<=right&&arr[left]%2!=0) left++;
while(left<=right&&arr[right]%2==0) right--;
if(left<=right) {
int temp = arr[left];
arr[left]=arr[right];
arr[right]=temp;
}
}
}
}
3、思路
(1)类似于快排,两个指针分别指向前后,找到第一个奇数、第一个偶数,交换顺序,直到指针交叉
4、注意点
(1)在外层while循环过程中,注意交换之前先判断一下left与right,有可能在最后一次中进行了交叉,再交换就破坏了顺序。
4、找第k大数
1、问题
在一个数组中以较高的效率找出第k大的元素
2、代码
package com.lanqiao.vidio;
public class SelectK {
public static void main(String[] args) {
int[] arr = {8,5,4,9,3,6};
int a = select(arr,3,0,arr.length-1);
System.out.println(a);
}
private static int select(int[] arr, int k,int i,int j) {
int p = petition(arr,i,j);
int pK = p+1;//主元是第几个元素
if(pK>k)
{
return select(arr,k,i,p-1);//注意return方法否则继续执行
}else if(pK<k){
return select(arr,k-pK,p+1,j);//在新序列中找元素
}else if(pK==k)
{
return arr[p];
}
return -1;
}
private static int petition(int[] arr, int i, int j) {
int pivot = arr[i];
int left = i+1;
int right = j;
while(left<=right)
{
while(left<=right&&arr[left]<pivot) left++;
while(left<=right&&arr[right]>pivot) right--;
if(left<=right)
{
Utils.swap(arr, left, right);
}
}
Utils.swap(arr, i, right);
return right;
}
}
3、思路
(1)类似于快排,快排每次确定的是枢轴所在位置,所在位置+1即第几大元素,当所找元素大小<枢轴所在位置+1,只在其左侧找,舍弃右侧,>同理
4、注意点
(1)每次找方法注意是return 方法 而不是直接调用方法
(2)在查找枢轴右侧时,在新序列中查找元素时,查找的元素位置与初始不同,是k-pK:k-p+1:就是在新序列中,原来查找的元素时第几位
5、查找数组中数目超过一半的数字
1、思路:
(1)既然是找超过一半的数字。肯定有一个数字的个数超过了总个数的一半,找到有序后中间值即可。
(2)利用确定第k大数的算法,找中间的数字即可
6、寻找最小可用ID
1、题目
在一个数组中,乱序排列(但1,2,3,4应该都有),找出一个数,在数组中没有出现且最小
2、思路
(1)找到中间的元素,看其大小是否=k+1(k:元素下标)
(2)=k+1:左半部分紧密,即元素都存在,舍弃,从其右半部分找
(3)>k+1:有半部分稀疏,即缺少元素,从左半部分找,如此往复,最终确定
7、排序时间复杂度
来源:CSDN
作者:唐荣
链接:https://blog.csdn.net/weixin_42673117/article/details/104090329