分治递归逆序数_【分治】逆序对计算-Count Inversion

本文介绍了如何使用分治算法解决逆序对计数问题。分别通过LeetCode剑指 Offer 51的例题和Count Inversion问题,阐述了在数组中找到逆序对的思路和代码实现,包括在满足特定条件下的逆序对计算。通过递归将数组二分并合并,优化时间复杂度。
摘要由CSDN通过智能技术生成

逆序对定义

如果存在正整数

使得

,而且

,则

这个有序对称为

的一个逆序对,也称作逆序数。

例题1 - LeetCode剑指 Offer 51. 数组中的逆序对

题目

在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。

输入: [7,5,6,4]

输出: 5

限制:0 <= 数组长度 <= 50000

思路

逆序对:<7,5>,<7,6>,<7,4>,<5,4>,<6,4>

1. 暴力枚举

数组中每个元素

与其后面每个元素

进行比较,若

则逆序对数量加1。

时间复杂度:

2. 分治

若数组元素个数为0或1,则该数组逆序对数量为0;若数组元素为有序,则该数组逆序对数量为0。可以发现,逆序对数量其实就是将无序数组排为有序后,数组元素交换的次数。

使用分治算法,递归将数组进行二分(low ~ middle 和 middle+1 ~ high),直至为仅剩1个元素。此时逆序对数量为0。再将数组(low ~ middle 和 middle+1 ~ high)两两依次合并,合并时若左半部分数组中的元素

,则逆序对数量增加

以题目为例:

逆序对.jpg

时间复杂度:

具体代码:

#include

using namespace std;

vector tmp;

long long int sum = 0;

long long int merge(vector &nums,int low,int mid,int high){

for (int i=low;i<=high;i++)

tmp[i] = nums[i];

int i = low;

int j = mid+1;

int k = low;

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

if (tmp[i]<=tmp[j])

nums[k++] = tmp[i++];

else {

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

sum += (mid-i+1);

}

}

while(i<=mid)

nums[k++] = tmp[i++];

while(j<=high)

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

return sum;

}

long long int mergeSort(vector &nums,int low,int high){

if (low == high)

return 0;

int mid=low+(high-low)/2;

mergeSort(nums,low,mid);

mergeSort(nums,mid+1,high);

return merge(nums,low,mid,high);

}

int main(){

int n,num;

vector nums;

scanf("%d",&n);

for (int i=0;i

scanf("%d",&num);

nums.push_back(num);

}

if (nums.size() < 2){

cout << sum << endl;

return 0;

}

tmp.resize(nums.size(),0);

printf("%lld",mergeSort(nums,0,nums.size()-1));

return 0;

}

例题2 - Count Inversion

Problem Description

Recall the problem of finding the number of inversions. As in the course, we are given a sequence of

numbers

and we define an inversion to be a pair

such that

We motivated the problem of counting inversions as a good measure of how different two orderings are. However, one might feel that this measure is too sensitive. Let's call a pair a significant inversion if

and

. Give an

algorithm to count the number of significant inversions between two orderings.

The array contains N elements

. All elements are in the range from 1 to 1,000,000,000.

Input

The first line contains one integer

, indicating the size of the array. The second line contains

elements in the array.

· 50% test cases guarantee that

Output

Output a single integer which is the number of pairs of significant inversions.

Sample Inout

6

13 8 5 3 2 1

Sample Output

6

题意与例题1相同,只不过增加一个限定条件:

,但此时使用分治算法后,将数组(low~middle 和 middle+1~high)两两依次合并时,合并时若左半部分数组中的元素

大于右半部分数组元素

,且

则逆序对数量增加

。即,不能仅仅通过比较

就增加逆序对数量,如进行

合并时,虽然

但是5后面的元素还存在大于3*2的元素,所以此时需要遍历左半部分数组,直至出现第一个大于三倍

的元素。因此需在原代码基础上进行修改。

#include

using namespace std;

vector tmp;

long long int sum = 0;

long long int merge(vector &nums,int low,int mid,int high){

for (int i=low;i<=high;i++)

tmp[i] = nums[i];

int i = low;

int j = mid+1;

int k = low;

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

if (tmp[i] <= tmp[j])

nums[k++] = tmp[i++];

else {

int pos = i;

while (pos <= mid){

if (tmp[pos] > (long long)3*tmp[j]){//此处为了避免乘以3后超出范围采用long long强制转换。(OJ没满分就因为这。)

sum += (mid-pos+1);

break;

}

pos++;

}

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

}

}

while(i<=mid)

nums[k++] = tmp[i++];

while(j<=high)

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

return con;

}

long long int mergeSort(vector &nums,int low,int high){

if (low == high)

return 0;

int mid = low+(high-low)/2;

mergeSort(nums,low,mid);

mergeSort(nums,mid+1,high);

return merge(nums,low,mid,high);

}

int main(){

int n,num;

vector nums;

scanf("%d",&n);

for (int i=0;i

scanf("%d",&num);

nums.push_back(num);

}

if (nums.size() < 2){

cout << sum << endl;

return 0;

}

tmp.resize(nums.size(),0);

printf("%lld",mergeSort(nums,0,nums.size()-1));

return 0;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值