package com.example.demo.algorithm.D003;
/**
* @Description :
* 逆序对问题:理解归并排序的精髓
*
* 在一个数组中,一个数比右边的数大,则这两个数称为逆序对,返回数组逆序对的个数
* 例子:[3,1,7,0,2]
* 3的逆序对:3:1 3:0 3:2
* 1的逆序对:1:0
* 7的逆序对:7:0 7:2
* 0的逆序对:没有
* 2的逆序对:没有
* 逆序对的个数为:3 + 1 + 2 = 6
*
* 流程:
* 左组的数比右组的数大,产生逆序对 -> 右组的数比左组的数小,产生逆序对 -> 左组有多少个数比右组大,那么就产生多少对逆序对
* 1、左组去marge,返回逆序对的个数
* 2、右组去marge,返回逆序对的个数
* 3、左组和右组marge,返回逆序对的个数
*
* [3,1,7,0,2]
* 1、317 merge
* 317
* 3 17
* 3 > 1 产生逆序对 31 p2++
* 3 7 不产生逆序对 p1++
*
* 2、02 merge
* 0 < 2 不产生逆序对 p1++
* 3、31702 merge
* 137 02
* 1 > 0 产生逆序对 10 30 70 p2++
* 137 2
* 1 < 2 不产生逆序对 p1++
* 37 2
* 3 > 2 产生逆序对 32 72 p2++
*
* @Author : Darren
* @Date : 2021 年 02 月 21 日 18:35:44
* @since : 1.0
*/
public class J003_InversionPair {
public static void main(String[] args) {
int testTime = 500000;
int maxSize = 100;
int maxValue = 100;
boolean succeed = true;
for (int i = 0; i < testTime; i++) {
int[] arr1 = generateRandomArray(maxSize, maxValue);
int[] arr2 = copyArray(arr1);
if (inversionPair(arr1) != inversionPair2(arr2)) {
succeed = false;
printArray(arr1);
printArray(arr2);
break;
}
}
System.out.println(succeed ? "Nice!" : "Fucking fucked!");
}
public static int inversionPair(int[] arr){
if (arr == null || arr.length < 2){
return 0;
}
return process(arr, 0, arr.length - 1);
}
public static int inversionPair2(int[] arr){
if (arr == null || arr.length < 2){
return 0;
}
int res = 0;
for (int i = 1; i < arr.length; i++) {
for (int j = 0; j < i; j++) {
res += arr[j] > arr[i] ? 1 : 0;
}
}
return res;
}
private static int process(int[] arr, int l, int r) {
//只有一个数,不产生逆序对
if (l == r){
return 0;
}
int mid = l + ((r - l) >> 1);
//l …… mid的逆序对个数 + mid+1……r的逆序对个数 + l……r的逆序对个数
return process(arr, l, mid)
+ process(arr, mid + 1, r)
+ marge(arr, l, mid, r);
}
private static int marge(int[] arr, int l, int mid, int r) {
int[] help = new int[r - l + 1];
int i = 0;
int p1 = l;
int p2 = mid + 1;
int res = 0;
while (p1 <= mid && p2 <= r){
// 左组有多少个数比右组大,那么就产生多少对逆序对
// 左组数小于右组的数,不产生逆序对,拷贝右组的数到help数组,右组下标++
// 左组数大于右组的数,产生逆序对的个数为左组下标开始数有n个数比右组大(因为有序),拷贝左组的数到help数组,左组下标++
res += arr[p1] <= arr[p2] ? 0 : (mid - p1 + 1);
help[i++] = arr[p1] <= arr[p2] ? arr[p1++] : arr[p2++];
}
while (p1 <= mid){
help[i++] = arr[p1++];
}
while (p2 <= r){
help[i++] = arr[p2++];
}
for (int i1 = 0; i1 < help.length; i1++) {
arr[l + i1] = help[i1];
}
return res;
}
/**
* 生成一个随机数组
* @param maxSize
* @param maxValue
* @return
*/
public static int[] generateRandomArray(int maxSize, int maxValue){
//Math.random() [0,1)
//Math.random() * N [0,N)
//(int)(Math.random() * N) [0,N-1]
int[] arrays = new int[(int) ((maxSize+1) * Math.random())];
for (int i = 0; i < arrays.length; i++) {
arrays[i] = (int) ((maxValue+1) * Math.random()) - (int)(maxValue * Math.random());
}
return arrays;
}
/**
* 打印数组
* @param arrays
*/
public static void printArray(int[] arrays){
if (arrays == null){
return;
}
for (int i = 0; i < arrays.length; i++) {
System.out.print(arrays[i] + " ");
}
System.out.println();
}
/**
* 复制数组
*/
public static int[] copyArray(int[] arr){
if (arr == null){
return null;
}
int[] res = new int[arr.length];
for (int i = 0; i < arr.length; i++) {
res[i] = arr[i];
}
return res;
}
/**
* 判断两个数组是否相等
* @param arr1
* @param arr2
* @return
*/
public static boolean isArrayEqual(int[] arr1, int[] arr2){
if ((arr1 == null && arr2 != null) || (arr1 != null && arr2 == null)){
return false;
}
if (arr1 == null && arr2 == null){
return true;
}
if (arr1.length != arr2.length){
return false;
}
for (int i = 0; i < arr1.length; i++) {
if (arr1[i] != arr2[i]){
return false;
}
}
return true;
}
}
标签:arr,数比,int,个数,mid,++,数组,逆序
来源: https://blog.csdn.net/axin1240101543/article/details/114089946
本站声明:
1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。