编程求逆序数

编程求逆序数

    逆序数,也就是一个排列中当某一对元素的先后次序与标准次序(从小到大)不同时,就说它构成一个逆序。

    如:3 5 2 1 4 的逆序数:2+3+1+0+0=6   ,3与2,1; 5与2,1,4; 2与1,就是找出排列第i个数后有几个比它小的数,有几个就有几个逆序数,遍历该排列,找出所有逆序数并求和就是该排列的总逆序数。

    话不多说,直接上代码

#include<stdio.h>
int count=0; 
int main()
{
	int n = 5;
	int a[n] = {3,5,2,1,4};	
	
	for(int i = 0; i < n; i++)
		for(int j = i; j < n; j++)
		{
			if(a[i]>a[j])
				count++;	
		}
	printf("count = %d\n",count);
	return 0;	
} 

上述方法的时间复杂度为O(N^2)

下面是基于归并排序的求逆序数的方法,比较关键的步骤是合并,合并步骤是将已两个排好序的数组进行合并,当a[i]>a[j]时,i到mid间的数都大于a[j],把a[j]放到a[i]前面时,就产生了mid-i+1个逆序数,此时做累加记录,若a[i]<a[j]时不产生逆序数。

#include<stdio.h>
#define N 10
int count = 0;
 
void merge(int a[],int left,int mid,int right)
{
	int i = left,j = mid+1,k = left;
	int b[N];
	
	while((i<=mid) && (j<=right))
	{
		if(a[i]>a[j])
		{
			b[k] = a[j++];
			count += mid-i+1;	
		}
		else
		{
			b[k] = a[i++];
		}
		k++;
	}
	
	while(i<=mid)
		b[k++] = a[i++];
	while(j<=right)
		b[k++] = a[j++];	
	for(int t = left;t<=right; t++)
		a[t] = b[t];
}
 
void reverse_count(int a[],int left,int right)
{
	if(left<right)
	{
		int mid = (left+right)/2;
		reverse_count(a,left,mid);
		reverse_count(a,mid+1,right);
		merge(a,left,mid,right);
	} 
} 
 
int main()
{
	int n = 5;
	int a[n] = {3,5,2,1,4};	
	reverse_count(a,0,4);
	printf("count = %d\n",count);
	return 0;	
} 

该方法基于归并排序,时间复杂度为O(NlogN)。

2021.4.14,笔试题,以下是java版本;

原题:输入n,m,

对前2^n个数操作m次,第m次输入一个数k,表示对这2^n个数,没2^k次进行一次翻转;求逆序对数

例如,输入:

n=2,m=3,接着输入

k=2,

k=1

k=2

输出:

6

4

2

解释:

初始序列为:1,2,3,4

第一次操作:4,3,2,1,逆序数对为6

第二次操作:3,4,1,2,逆序数对为4

第三次操作:2,1,4,3,逆序数对为2

图解:

import java.util.ArrayList;
import java.util.Scanner;

class Solusion2{
    private final  int maxlen = 1000001;
    private int[] tmp = new int[maxlen];

    private int cnt = 0;

    public void nixu(ArrayList<Integer> arr,int left,int right){
        if(left>=right){
            return;
        }
        int mid = left + (right-left)/2;
        nixu(arr,left,mid);
        nixu(arr,mid+1,right);
        merge(arr,left,mid,right);
    }


    public void merge(ArrayList<Integer> arr,int left,int mid,int right){
        int p = left,q=mid+1;
        int k = 0;
        while(p<=mid && q<=right){
            if(arr.get(p)>arr.get(q)){
                //arr[q]和mid前面每一个数都能组成逆序数对
                this.cnt += mid-p+1;
                tmp[k++] = arr.get(q);
                q++;
            }else{
                tmp[k++] = arr.get(p);
                p++;
            }
        }
        while(p<=mid){
            tmp[k++] = arr.get(p);
            p++;
        }
        while(q<=right){
            tmp[k++] = arr.get(q);
            q++;
        }
        for(int i=0;i<k;i++){
            arr.set(left+i,tmp[i]);
        }
    }

    public void setCnt(int cnt){
        this.cnt = cnt;
    }
    public int getCnt(){
        return this.cnt;
    }
}

public class problem1 {

    final  int maxlen = 1000001;

    public static void main(String[] args) {

        Solusion2 solusion2 = new Solusion2();

        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int m = sc.nextInt();
        ArrayList<Integer> arr = new ArrayList<>();

        for(int i=0;i<Math.pow(2,n);i++){
            arr.add(i+1);
        }

        for(int i=0;i<m;i++){
            int j = sc.nextInt();
            int powlen = (int) Math.pow(2,j);
            //反转
            int p = 0;

            while(p<arr.size()){
                int left=p,right=p+powlen-1;
                if(right>arr.size()){
                    break;
                }
                while(left<right)
                {
                    int tmp = arr.get(left);
                    arr.set(left, arr.get(right));
                    arr.set(right, tmp);
                    left++;
                    right--;
                }
                p+=powlen;
            }

            //暴力法求逆序对
//            int cnt = 0;
//            for(int q=1;q<arr.size();q++){
//                for(int w=0;w<q;w++){
//                    if(arr.get(w)>arr.get(q)){
//                        cnt++;
//                    }
//                }
//            }
            ArrayList<Integer> arr1 = new ArrayList<>(arr);

            solusion2.nixu(arr,0,arr.size()-1);
            System.out.println(solusion2.getCnt());
            solusion2.setCnt(0);

            arr.clear();
            arr.addAll(arr1);
        }

        sc.close();
    }
}

 

 

 

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值