逆序对的个数java_AcWing 788. 基础_归并_逆序对的数量java_python_c++

题目描述

给定一个长度为n的整数数列,请你计算数列中的逆序对的数量。

逆序对的定义如下:对于数列的第 i 个和第 j 个元素,如果满足 i < j 且 a[i] > a[j],则其为一个逆序对;否则不是。

输入格式

第一行包含整数n,表示数列的长度。

第二行包含 n 个整数,表示整个数列。

输出格式

输出一个整数,表示逆序对的个数。

数据范围

1≤n≤100000

输入样例:

6

2 3 4 5 6 1

输出样例:

5

观众老爷们,如果本思路对您有帮助,求关注一波~~~

思路

在两个区间合并过程中,出现逆序对的情况只能在两个区间进行数值的比较

初始, 逆序对的个数为res = 0

举例

[l, mid] 1, 2, 4, 4 l = 0 mid = 3

[mid + 1, r] 2, 3, 4, 5, mid + 1 = 4 r = 7

i j

1. 1(1) < 2(4) tmp = [1] res = 0

2. 2(2) <= 2(4) tmp = [1, 2] res = 0

3. 4(3) > 2(4) tmp = [1, 2, 2] res += 3 - 2 + 1 = 2 左边区间是有序的 对于当前点2, 左区间比4大的元素也 > 2,所以 res = mid - i + 1

4. 4(3) > 3(5) tmp = [1, 2, 2, 3] res += 3 - 2 + 1 = 4

5. 4(3) <= 4(6) tmp = [1, 2, 2, 3, 4] res = 4

6. 4(4) <= 4(6) tmp = [1, 2, 2, 3, 4, 4] res = 4 i遍历完成,很容易发现在右区间剩余元素4, 5必然大于左区间最后一个元素,无法构成逆序对

7.将剩余元素添加到tmp tmp = [1, 2, 2, 3, 4, 4, 4, 5]

8.更新tmp数组到原数组的[1, r]区间,这里也变相的说明了为什么左右区间一开始就是有序的

LL merge_sort(int l, int r){

if(l >= r) return 0;

int mid = l + r >> 1;

LL res = merge_sort(l, mid) + merge_sort(mid + 1, r);

int k = 0, i = l, j = mid + 1;

while(i <= mid && j <= r){

if(q[i] <= q[j]) tmp[k ++] = q[i ++];

else {

tmp[k ++] = q[j ++];

//q[j] > q[i],对于q[j],mid的左边有mid - i + 1个数与q[j]组成逆序对

res += mid - i + 1;

}

}

while(i <= mid) tmp[k ++] = q[i ++];

while(j <= r) tmp[k ++] = q[j ++];

for(int i = l, k = 0; i <= r; i ++, k ++) q[i] = tmp[k];

return res;

}

java 代码

import java.util.Scanner;

public class Main{

static int n;

static int N = 100010;

static int[] q = new int[N], tmp = new int[N];

public static void main(String[] args){

Scanner sc = new Scanner(System.in);

n = sc.nextInt();

for(int i = 0; i < n; i ++) q[i] = sc.nextInt();

long res = mergeSort(q, 0, n - 1);

System.out.println(res);

}

public static long mergeSort(int[] q, int l, int r){

if(l >= r) return 0;

int mid = l + r >> 1;

long res = mergeSort(q, l, mid) + mergeSort(q, mid + 1, r);

int k = 0, i = l, j = mid + 1;

while(i <= mid && j <= r){

if(q[i] <= q[j]) tmp[k ++] = q[i ++];

else{

res += mid - i + 1;

tmp[k ++] = q[j ++];

}

}

while(i <= mid) tmp[k ++] = q[i ++];

while(j <= r) tmp[k ++] = q[j ++];

for(i = l, k = 0; i <= r; i ++, k ++) q[i] = tmp[k];

return res;

}

}

python3 代码

q = [0] * 100010

tmp = [0] * 100010

def mergeSort(q, l, r):

if(l >= r): return 0

mid = l + r >> 1

res = mergeSort(q, l, mid) + mergeSort(q, mid+1, r)

k = 0; i = l; j = mid + 1

while(i <= mid and j <= r):

if(q[i] <= q[j]):

tmp[k] = q[i]

k += 1; i += 1

else:

res += mid - i + 1

tmp[k] = q[j]

k += 1; j += 1

while(i <= mid):

tmp[k] = q[i]

k += 1; i += 1

while(j <= r):

tmp[k] = q[j]

k += 1; j += 1

k = 0; i = l

while(i <= r):

q[i] = tmp[k]

i += 1; k += 1

return res

def main():

global q

n = int(input())

q = list(map(int, input().split()))

res = mergeSort(q, 0, n - 1)

print(res)

main()

C++ 代码

#include

using namespace std;

typedef long long LL;

const int N = 1e6 + 10;

int n;

int q[N], tmp[N];

LL merge_sort(int l, int r){

if(l >= r) return 0;

int mid = l + r >> 1;

LL res = merge_sort(l, mid) + merge_sort(mid + 1, r);

int k = 0, i = l, j = mid + 1;

while(i <= mid && j <= r){

if(q[i] <= q[j]) tmp[k ++] = q[i ++];

else {

tmp[k ++] = q[j ++];

//q[j] > q[i],对于q[j],mid的左边有mid - i + 1个数与q[j]组成逆序对

res += mid - i + 1;

}

}

while(i <= mid) tmp[k ++] = q[i ++];

while(j <= r) tmp[k ++] = q[j ++];

for(int i = l, k = 0; i <= r; i ++, k ++) q[i] = tmp[k];

return res;

}

int main(){

cin >> n;

for(int i = 0; i < n; i ++) cin >> q[i];

cout << merge_sort(0, n - 1) << endl;

return 0;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值