求中点:mid=L+(R-L)>>1
递归
在范围内求最大值:
递归行为时间复杂度估算:master公式
归并排序
归并排序:将数组分成两部分,分别对两部分进行排序,将排好序的两部分利用双指针合并成一个数组(需要一个外部空间),最后将外部空间的数组拷贝到原数组中。对每部分的排序采用递归的方式进行。
代码实现:
public class MergeTest {
public static void main(String[] args) {
int[] arr={2,3,5,1,7,4};
//测试
process(arr,0,arr.length-1);
for (int i=0;i<arr.length;i++){
System.out.println(arr[i]);
}
}
public static void process(int[] arr,int L,int R){
if(L==R){
return;
}
int mid=L+((R-L)>>1); //异或运算求中点
//递归调用
process(arr, L, mid);
process(arr, mid+1, R);
merge(arr,L,mid,R);
}
//利用辅助空间进行排序操作
public static void merge(int[] arr,int L,int M,int R){
//定义一个辅助空间用来存放merge后的数组
int[] help=new int[R-L+1];
int i=0,p1=L,p2=M+1;
//都不越界
while (p1<=M && p2<=R){
//双指针,如果左侧小于等于右侧,就把左侧数据放入辅助空间中,反之亦然
help[i++]=arr[p1]<=arr[p2]?arr[p1++]:arr[p2++];
}
//左侧未越界,说明右侧越界了,则把左侧剩余的数据直接放到辅助空间
while (p1<=M){
help[i++]=arr[p1++];
}
//同理,两个while只会执行一个
while (p2<=R){
help[i++]=arr[p2++];
}
//从L开始
for (int j=0;j< help.length;j++){
arr[L+j]=help[j];
}
}
}
合并有序数组
题目描述:
题解:
class Solution {
public:
void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
int p1=0,p2=0;
int res[m+n];
int cur;
while(p1<m || p2<n){
if(p1==m){
cur=nums2[p2++];
}else if(p2==n){
cur=nums1[p1++];
}else if(nums1[p1]<nums2[p2]){
cur=nums1[p1++];
}else{
cur=nums2[p2++];
}
res[p1+p2-1]=cur;
}
for(int i =0;i!=m+n;i++){
nums1[i]=res[i];
}
}
};
小和问题
小和问题:在一个数组中,每个数左边比当前数小的数累加起来,叫做这个数组的小和。求一个数组的小和。
例子:数组[1,3,4,2,5]中,1左边比1小的数,没有;3左边比3小的数,1;4左边比4小的数,1、3;2左边比2晓得数,1;5左边比5小的数,1、3、4、2;所以小和为1+1+3+1+1+3+4+2=16。
解法思路:采用递归的方式分为左右两个数组,则左边的数组产生的小和+右边的数组产生的小和+左右数组合并产生的小和就为最终的结果。
public class SmallSum {
public static void main(String[] args) {
int[] arr={3,6,8,4,5};
int ss=smallSum(arr);
System.out.println(ss);
}
public static int smallSum(int[] arr){
if(arr==null || arr.length<2){
return 0;
}
return mergeSort(arr,0,arr.length-1);
}
public static int mergeSort(int[] arr,int l,int r){
if(l==r){
return 0;
}
int mid=l+((r-l)>>1);
return mergeSort(arr,l,mid)+
mergeSort(arr,mid+1,r)+
merge(arr,l,mid,r);
}
public static int merge(int[] arr,int l,int m,int r){
//辅助空间
int[] help=new int[r-l+1];
int i=0,p1=l,p2=m+1;
int res=0;
//都不越界
while (p1<=m && p2<=r){
//边界值判断,如果左右两侧值相等的话,应该是右侧指针右移
res+=arr[p1]<arr[p2]?(r-p2+1)*arr[p1]:0;
help[i++]=arr[p1]<arr[p2]?arr[p1++]:arr[p2++];
}
//有一侧越界
while (p1<=m){
help[i++]=arr[p1++];
}
while (p2<=r){
help[i++]=arr[p2++];
}
for (int j=0;j<help.length;j++){
arr[l+j]=help[j];
}
return res;
}
}
逆序对问题
题目描述:
题解:
public class nxd {
public static void main(String[] args) {
int[] arr={7,5,6,4};
int ss=smallSum(arr);
System.out.println(ss);
}
public static int smallSum(int[] arr){
if(arr==null || arr.length<2){
return 0;
}
return mergeSort(arr,0,arr.length-1);
}
public static int mergeSort(int[] arr,int l,int r){
if(l==r){
return 0;
}
int mid=l+((r-l)>>1);
return mergeSort(arr,l,mid)+
mergeSort(arr,mid+1,r)+
merge(arr,l,mid,r);
}
public static int merge(int[] arr,int l,int m,int r){
//辅助空间
int[] help=new int[r-l+1];
int i=0,p1=l,p2=m+1;
int res=0;
//都不越界
while (p1<=m && p2<=r){
//边界值判断,如果左右两侧值相等的话,应该是右侧指针右移
res+=arr[p1]>arr[p2]?(m-p1+1):0;
help[i++]=arr[p1]>arr[p2]?arr[p2++]:arr[p1++];
}
//有一侧越界
while (p1<=m){
help[i++]=arr[p1++];
}
while (p2<=r){
help[i++]=arr[p2++];
}
for (int j=0;j<help.length;j++){
arr[l+j]=help[j];
}
return res;
}
}