算法学习笔记-递归问题的深入探讨/归并排序算法/小和问题算法
说到这个问题呢,其实我们脑子里是不是第一感受是:
递归吗,自己调用自己咯。
在逻辑上讲,这没错,但事实又是如何呢,那我们进入第一个问题
递归问题的深入探讨
我们先来看一段代码吧
int GetMax(int*Array,int Leftindex,int Rightindex){
if(Leftindex==Rightindex)return Array[Leftindex];
int minndex=(Leftindex+Rightindex)/2;
return max(GetMax(Array,Leftindex,minndex),GetMax(Array,minndex+1,Rightindex));
}
int GetMin(int*Array,int Leftindex,int Rightindex){
if(Leftindex==Rightindex)return Array[Leftindex];
int minndex=(Leftindex+Rightindex)/2;
return min(GetMin(Array,Leftindex,minndex),GetMin(Array,minndex+1,Rightindex));
}
java
代码如下
GetMaxValue .java
package sort;
/**
* The type Get max value.
*
* @author user
*/
public class GetMaxValue {
/**
* Maxvalue int.
*
* @param array the array
* @param lefties the lefties
* @param righted the righted
* @return the int
*/
public static int maxvalue(int[] array, int lefties, int righted) {
if (lefties == righted) {
return array[lefties];
}
int index=(lefties+righted)>>1;
return Math.max(maxvalue(array,lefties,index),maxvalue(array,index+1,righted));
}
/**
* Disorder int.
*
* @param args the args
* @return the int
*/
public static int disorder(int[] args) {
int maxValue =args[0];
for (int i = 1; i < args.length; i++) {
if (args[i] > maxValue) {
maxValue = args[i];
}
}
return maxValue;
}
/**
* Generate array int [ ].
*
* @return the int [ ]
*/
public static int[] generateArray() {
int maxValue = 123,minValue =1,randomMaximum=11, randomMinimum =-2;
int length = (int) (Math.random() * maxValue)+minValue;
int[] result = new int[length];
for (int i = 0; i != length; i++) {
result[i] = (int) (Math.random() * randomMaximum) + randomMinimum;
}
return result;
}
/**
* The entry point of application.
*
* @param args the input arguments
*/
public static void main(String[] args) {
int testTime = 10000;
boolean inorder= true;
for (int i = 0; i <testTime; i++) {
int[] array = generateArray();
int maxValue = maxvalue(array, 0, array.length-1);
if (disorder(array) != maxValue) {
inorder = false;
break;
}
}
if (inorder) {
System.out.println("666666");
}else {
System.out.println("333333");
}
}
}
GetMinValue .java
package sort;
/**
* The type Get min value.
*
* @author user
*/
public class GetMinValue {
/**
* Minvalue int.
*
* @param array the array
* @param lefties the lefties
* @param righted the righted
* @return the int
*/
public static int minvalue(int[] array, int lefties, int righted) {
if (lefties == righted) {
return array[lefties];
}
int index=(lefties+righted)>>1;
return Math.min(minvalue(array,lefties,index),minvalue(array,index+1,righted));
}
/**
* Disorder int.
*
* @param args the args
* @return the int
*/
public static int disorder(int[] args) {
int maxValue =args[0];
for (int i = 1; i < args.length; i++) {
if (args[i] < maxValue) {
maxValue = args[i];
}
}
return maxValue;
}
/**
* Generate array int [ ].
*
* @return the int [ ]
*/
public static int[] generateArray() {
int maxValue = 123,minValue =1,randomMaximum=11, randomMinimum =-2;
int length = (int) (Math.random() * maxValue)+minValue;
int[] result = new int[length];
for (int i = 0; i != length; i++) {
result[i] = (int) (Math.random() * randomMaximum) + randomMinimum;
}
return result;
}
/**
* The entry point of application.
*
* @param args the input arguments
*/
public static void main(String[] args) {
int testTime = 10000;
boolean inorder= true;
for (int i = 0; i <testTime; i++) {
int[] array = generateArray();
int maxValue = minvalue(array, 0, array.length-1);
if (disorder(array) != maxValue) {
inorder = false;
break;
}
}
if (inorder) {
System.out.println("666666");
}else {
System.out.println("333333");
}
}
}
其实我们不难发现,其实递归问题的算法可以改成非递归算法。
那递归的实质又是什么呢?
递归的实质是栈的自动的压入和弹出
不懂的话,请参见栈的压入和弹出。
master公式及其应用
t(n)=at(n/b)+O(n^d);
n为数据总量,b为平均分成几份,a为出现的次数,O(n^d)为额外时间复杂度
if(log(b,a))>d=>O(nlog(b,a);
else if(log(b,a)==d)=>O(n^d*log(b,a));
else log(b,a)<d =>O(n^d);
master前提:你划分的子过程的规模是一样的。
归并排序
对于上面的问题就说这么多吧,我们来思考一下,我们对于排序应该有一定理解吧,那相信大家一定也对归并排序有一定理解吧,那请允许我在这里给大家总结一下吧。
其实我们可以把归并排序看成二分法的用法之一,先左侧排好序,在右侧排好序,再用一个辅助数组进行操作。那它的时间复杂度又是多少呢。
它的时间复杂度为:O(nlog(b,a))*
话不多说,上代码吧:
void MergerSort(int Array[], int Lenght){
int *Arrayhelp = new int[Lenght];
mergeSortHelper(Array, Arrayhelp, 0, Lenght - 1);
delete[] Arrayhelp;
}
void Merger(int Array[], int Arrayhelp[], int Left, int Mid, int Right){
int i = Left,j = Mid + 1,k = Left;
while (k <= Right) {
if (i > Mid)Arrayhelp[k++] = Array[j++];
else if (j > Right)Arrayhelp[k++] = Array[i++];
else Arrayhelp[k++]=Array[i]>Array[j]?Array[j++]:Array[i++];
}
for (int k = Left; k <= Right; k++)Array[k] = Arrayhelp[k];
}
void mergeSortHelper(int Array[], int Arrayhelp[], int Left, int Right){
if (Left >= Right) return;
int Mid = (Left + Right)/2;
mergeSortHelper(Array, Arrayhelp, Left, Mid);
mergeSortHelper(Array, Arrayhelp, Mid + 1, Right);
Merger(Array, Arrayhelp, Left, Mid, Right);
}
java
代码如下
package sort;
import java.util.Arrays;
/**
* The type Sort merge sort.
* @author user
*/
public class SortMergeSort {
/**
* Get merge sort int [ ].
*
* @param array the array
* @return the int [ ]
*/
public static int[] getMergeSort(int[] array) {
int minIndex=2;
if (array == null || array.length <minIndex) {
return array;
}
return mergeSort(array, 0, array.length - 1);
}
private static int[] mergeSort(int[] arr, int left, int right) {
if (left == right) {
return arr;
}
int mid = left + ((right - left)>>1);
mergeSort(arr, left, mid) ;
mergeSort(arr, mid + 1, right);
return merge(arr, left, mid, right);
}
/**
* Merge int [ ].
*
* @param arr the arr
* @param left the left
* @param madder the madder
* @param right the right
* @return the int [ ]
*/
public static int[] merge(int[] arr, int left, int madder, int right) {
int[] help = new int[right - left + 1];
int i = 0,p1 = left,p2 = madder + 1;
while(p1 <= madder && p2 <= right) {
if (arr[p1] < arr[p2]) {
help[i++] = arr[p1++];
}else {
help[i++] = arr[p2++];
}
}
while(p1 <= madder) {
help[i++] = arr[p1++];
}
while(p2 <= right) {
help[i++] = arr[p2++];
}
System.arraycopy(help, 0, arr, left, help.length);
return arr;
}
/**
* Disorder boolean.
*
* @param args the args
* @return the boolean
*/
public static boolean disorder(int[] args) {
for (int i = 0; i < args.length-1; i++) {
if (args[i]>args[i+1]) {
return false;
}
}
return true;
}
/**
* Get random array int [ ].
*
* @return the int [ ]
*/
public static int[] getRandomArray() {
int[] res = new int[(int) (Math.random() * 20) + 1];
for (int i = 0; i < res.length; i++) {
res[i] = (int) (Math.random() * 20) + 1;
}
return res;
}
/**
* The entry point of application.
*
* @param args the input arguments
*/
public static void main(String[] args) {
int testTime = 10000;
boolean inorder= true;
for (int i = 0; i <testTime; i++) {
int[] array = getRandomArray();
getMergeSort(array);
if (!disorder(array)) {
System.out.println(Arrays.toString(Arrays.stream(array).toArray()));
inorder = false;
break;
}
}
if (inorder) {
System.out.println("666666");
}else {
System.out.println("333333");
}
}
}
小和问题算法问题
在一个数组中,每一个数左边比当前数小的数累加起来,叫做这个数组的小和。求一个数组的小和。
例子
[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
那思路又是什么呢:
这道题换个角度来想,题目要求的是每个数左边有哪些数比自己小,其实不就是右边有多少个数比自己大,那么产生的小和就是当前值乘以多少个吗?还是以上面的样例举例,1右边有4个比1大的数,所以产生小和14;3右边有2个比3大的数,所以产生小和32;4右边有一个比4大的数,所以产生小和41;2右边没有比2大的数,所以产生小和为20;5右边也没有比5大的数,所以产生小和5*0
算了,上代码吧:
int LittleSums(int a[], int len){
int *b = new int[len];
int Liltlesum=littlesum(a, b, 0, len - 1);
delete[] b;
return Liltlesum;
}
int mergeSum(int a[], int b[], int l, int m, int r){
int Sum=0,i = l,j = m + 1,k = l;
while (k <= r) {
if (i > m) b[k++] = a[j++];
else if (j > r) b[k++] = a[i++];
else {
if (a[i] > a[j]) b[k++] = a[j++];
else {
Sum+=a[i]*(r-j+1);
b[k++] = a[i++];
}
}
}
for(int k = l; k <= r; k++) a[k] = b[k];
return Sum;
}
java代码实现:
/**
* @version 0.1.2
* @since 2021/10/24
* @author Void Bug
*
* 问题描述:
* 在一个数组中,每一个数左边比当前数小的数累加起来,叫做这个数组的小和。求一个数组的小和。
* 例子
* [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
*
* 这道题换个角度来想,题目要求的是每个数左边有哪些数比自己小,
* 其实不就是右边有多少个数比自己大,
* 那么产生的小和就是当前值乘以多少个吗?
* 还是以上面的样例举例,1右边有4个比1大的数,
* 所以产生小和14;3右边有2个比3大的数,所以产生小和32;4右边有一个比4大的数,
* 所以产生小和41;2右边没有比2大的数,所以产生小和为20;
* 5右边也没有比5大的数,所以产生小和5*0
*
* 及我们先把左边右边都排好序,然后我们用左边的第0个值与右边第0个值的值
* 如果大,那么就产生了左边元素第0个值*右边的个数,以此类推即可
*
* 不理解的话请参照上图(小和问题图解)即可
*/
public class Problematic_01_small {
/**
* 得到小和的方法,我们把数组传入,得到我们想要的小和值 mergeSort为具体实现方法
* @param array 传入的数组
* @return 返回小和值
*/
public static int getSmallSum(int[] array) {
if (array == null || array.length < 2) {
return 0;
}
return mergeSort(array, 0, array.length - 1);
}
/**
* 小和值的实现方法,我先把两边排好序,然后进行归并排序并进行计算小和值
* mergeSort(arr, left, mid)/mergeSort(arr, mid + 1, right) 是把以中点断开左边和右边的数组进行拆分
* merge(arr, left, mid, right) 进行排序并且计算小和值
* @param arr 传入的数组
* @param left 左端点值
* @param right 右端点值
* @return 我们想要的小和值
*/
private static int mergeSort(int[] arr, int left, int right) {
if (left == right) {
return 0;
}
int mid = left + ((right - left)>>1);
return mergeSort(arr, left, mid)
+ mergeSort(arr, mid + 1, right)
+ merge(arr, left, mid, right);
}
/**
* 计算我们的小和值
* 1.我们先去声明一个辅助数组
* 2.我们去定义两个游标,让其中一个,本程序中是p1指向左半数组的第一个元素,让p2指向右半数组的第一个元素,用res去记录产生的小和值
* 3.左边的游标值比右边的游标值小,则辅助数组中填入较小元素的值,并且计算出产生的小和值,小和值计算公式:(右边界到右游标的个数)个左标值
* 4.以此类推即可
* 5.当有一个游标到达左右的分水线时候,就说明了其中一个解决了,及全加到了array数组里面,我们把另一个加入即可
* 6.把辅助数组的值复制到原来的数组即可,返回小和并且返回我们的排好序的数组即可
*
* 其实我们不难发现这与归并排序很像,几乎就没有差别,这个不难理解,我么不同的是就一个计算我们的小和即可
*
* @param arr 传入的数组
* @param left 左端点值
* @param right 右端点值
* @param madder 中点位置
* @return 返回我们的小和值并进行归并排序
*/
private static int merge(int[] arr, int left, int madder, int right) {
int[] help = new int[right - left + 1];
int i = 0,p1 = left,p2 = madder + 1,res = 0;
while(p1 <= madder && p2 <= right) {
if (arr[p1] < arr[p2]) {
res = res + arr[p1] * (right - p2 + 1);
help[i++] = arr[p1++];
}else {
help[i++] = arr[p2++];
}
}
while(p1 <= madder) {
help[i++] = arr[p1++];
}
while(p2 <= right) {
help[i++] = arr[p2++];
}
System.arraycopy(help, 0, arr, left, help.length);
return res;
}
/**
* 数组的对数器:生成随机数组,不定长不定值正整型数组
* @return 返回生成的数组
*/
public static int[] getRandomArray() {
int[] res = new int[(int) (Math.random() * 20) + 1];
for (int i = 0; i < res.length; i++) {
res[i] = (int) (Math.random() * 20) + 1;
}
return res;
}
/**
* 主方法
* @param args 输入的信息
* 测试方法
*/
public static void main(String[] args) {
int[] arr = {1,3,4,2,5};
System.out.println(getSmallSum(arr));
}
}
小和问题呢,个人感觉,难又不难,简单又不简单,虽然是写的不太好,但还是希望大家见谅吧。