首页 > 编程语言 >归并算法及求逆序对例题

归并算法及求逆序对例题

时间:2022-10-09 09:55:58浏览次数:59  
标签:数列 int mid 数组 guibing 例题 及求 逆序

归并算法及求逆序对例题

归并算法

思路


  1. 首先先确定分界点mid,分界点为mid = (l + r) /2,也就是整个数列的中间,将整个数列通过这个分界点一分为二。
  2. 分别递归左右两个序列,将两个无序序列变为有序序列
  3. 再分别将左右两个有序序列合并为一个有序序列

​ 3.1 首先先将两个指针i,j分别指向两个序列中的最小值(也就是两个序 列的最左边)

​ 3.2然后分别比较i指针所指的数和j指针所指的数,并将两个数中较小的 数放入一个临时数组tmp,并将放入数对应的指针向后移动,重新 进行比较i和j所指数字,(如果i指针所指数字进入tmp,那就将i指 针向后移动一位,重新和j比较)

​ 3.3 循环这个过程知道两个数组中有一个数组全部排入tmp中 ,然后将 另一个数组中剩余的数组全部接入tmp

代码如下

#include <iostream>

using namespace std;

const int N = 100010;

int n;
int a[N], tmp[N];

void guibing(int q[], int l, int r){
    
    if(l == r) return;
    
    int mid = (l + r) / 2;
    
    guibing(q, l, mid);
    guibing(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 tmp[k ++] = q[j ++];
    
    while(i <= mid) tmp[k ++] = q[i ++];
    while(j <= r) tmp[k ++] = q[j ++];
    
    for(i = l, j = 0; i <= r; i ++, j ++) q[i] = tmp[j];
}

int main(){
    scanf("%d", &n);
    for(int i = 0; i < n; i++) scanf("%d", &a[i]);
    
    guibing(a, 0 ,n - 1);
    
    for(int i = 0; i < n; i++) printf("%d ", a[i]);
}

逆序对数量例题

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

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

输入格式

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

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

输出格式

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

数据范围

1≤n≤1000001≤n≤100000,
数列中的元素的取值范围 [1,109][1,109]。

输入样例:

6
2 3 4 5 6 1

输出样例:

5


解题思路

  1. 首先先将整个数列一分为二

  2. 一共可能有三种情况,两个数字都在左边的数组;两个数字都在右边的数组;一个数字在左边的数组,一个数字在右边的数组。

  3. 都在左边的数量一共就是归并排序的数量也就是guibing(q, l, mid);

  4. 都在右边的数量一共就是归并排序的数量也就是guibing(q, mid + 1, r);

  5. 一左一右的情况的数量就是:右边每个数字的逆序对成立条件的总和

    (每个数字的数量就是 mid - i + 1)用循环进行计算。

代码如下

#include <iostream>

using namespace std;

typedef long long LL;

const int N = 100010;

int n;
int q[N], tmp[N];

LL guibing(int q[], int l, int r){



    if(l == r) return 0;

    int mid = (l + r) /2;

    LL num = guibing(q, l, mid) + guibing(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 {
            num += mid - i + 1;
            tmp[k ++] = q[j ++];
        }
    }

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

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

    return num;
}

int main(){

    scanf("%d", &n);

    for(int i = 0; i < n; i ++) scanf("%d" ,&q[i]);

    cout << guibing(q, 0, n - 1) << endl;

    return 0;

}


标签:数列,int,mid,数组,guibing,例题,及求,逆序
From: https://www.cnblogs.com/xiaofenga/p/16771108.html

相关文章

  • 788. 逆序对的数量
    https://www.acwing.com/problem/content/description/790/y总的思路我的理解究其分治,底层原理,大概是:利用归并排序的分治特点,一次分两组最终分成单位为1,即只有1个数......
  • 快速排序模板及快速选择例题
    快速排序模板及快速选择例题快速排序思路首先选择出分界值,x=q[l]或q[r]或q[(l+r)/2];将整个数组分为左右两段,使得左边的所有数都<=x,右边的所有数都>=x2.......
  • 树状数组-归并排序-逆序对-2426. 满足不等式的数对数目
    问题描述给你两个下标从0 开始的整数数组 nums1和 nums2 ,两个数组的大小都为 n ,同时给你一个整数 diff ,统计满足以下条件的 数对 (i,j) :0<=i<j<=n-......
  • 字符串哈希 模板 例题
    字符串哈希可以快速判断两个子字符串是否相等原理:https://www.cnblogs.com/ydUESTC/p/15722400.html注意字符串哈希时后面的字符视为低位,这样方便取一段字符的哈希时先......
  • 矩阵乘法(快速幂)结合dp结合除法逆元的例题
    https://atcoder.jp/contests/abc271/tasks/abc271_g题目的思路为:构建dp矩阵,dp[i][j][k]表示开始前停在j,结束后停在k,且停下时恰好出现2^i次访问的概率则dp[i]=dp[i-1]*d......
  • 01背包&完全背包二维写法的对比,进而理解一维优化后的正逆序
    01背包题解完全背包题解二维写法时两种背包问题核心代码的区别:可以看出,01背包用的是上一层的数据,完全背包用的是当前层的数据所以优化为一维时,01背包需逆序for......
  • 误差理论与测量平差基础——例题补充推导
    本次补充推导的是第三章的第六道例题,主要做出的补充推导内容是几个方差计算公式的内容,下面是补充内容  ......
  • 计算五位数的逆序数
    #include<stdio.h>intmain(){longa;//输入一位五位数 intg,h,m,k,l;//依次获取各位数值 intn; //inti,j;//迭代值 intt=0;//逆序数 //intb;*/ printf("计......
  • 用递归函数和栈操作逆序栈
    用递归函数和栈操作逆序栈作者:Grey原文地址:博客园:用递归函数和栈操作逆序栈CSDN:用递归函数和栈操作逆序栈题目描述请设计一个算法实现逆序栈的操作,但是只能用递归函......
  • 整数的逆序
    思路:首先定义三个变量abc,让用户输入一个整数存放在变量a中     然后让a对10取余数得到其个位数,将这个个位数赋值给b     每次的a/10使得a每次丢到其各......