最少的交换 Java实现

目录

题目描述

输入

输出

样例输入

样例输出

问题分析

代码

题目描述

现在给你一个由n个互不相同的整数组成的序列,现在要求你任意交换相邻的两个数字,使序列成为升序序列,请问最少的交换次数是多少?

输入

输入包含多组测试数据。每组输入第一行是一个正整数n(n<500000),表示序列的长度,当n=0时,表示输入结束。
接下来的n行,每行一个整数a[i](0<=a[i]<=999999999),表示序列中第i个元素。

输出

对于每组输入,输出使得所给序列升序的最少交换次数。

样例输入

5

9

1

0

5

4

3

1

2

3

0

样例输出

6

0

问题分析

从题中看到关键点①相邻元素交换②排序(升序)求交换次数

根据示例可以知道要对数组进行排序,可以用冒泡排序,但是冒泡排序O(n^2)时间超限制

从这里可以看出,归并排序是最适合解该题的算法

仔细分析该题,其实是求逆序对的个数

逆序:一般认为从左向右序列的数字增大认为是正序的,那么从左到右序列的序列数字出现减小就认为是逆序的。一个“逆序”的数学定义是这样的,如果存在正整数 i, j 使得 1 ≤ i < j ≤ n 而且 A[i] > A[j],则 <A[i], A[j]> 这个有序对称为 A 的一个逆序,又称作一个逆序对。
逆序对:数学术语,设 A 为一个有 n 个数字的有序集 (n>1),其中所有数字各不相同。

如果存在正整数 i, j 使得 1 ≤ i < j ≤ n 而且 A[i] > A[j],则 <A[i], A[j]> 这个有序对称为 A 的一个逆序对,也称作逆序数

逆序列:给定n个数1,2,...,n的一个排列a1a2...an,令bi是数i在此排列中的逆序数,换句话说,bi等于该排列中先于i又大于i的那些数的个数。数列b1b2...bn称为排列a1a2...an的逆序数列(inversion sequence)。排列与逆序数列一一对应。例如排列32541的逆序数列是01014。解释如下:b5是4的原因为a5是1,它的前面有3、2、5、4,他们都大于1,所以有4个数大于1。b3是0的原因是a是5,它的前面有3、2,他们都小于5,所以有0个数大于5

归并排序可参考排序算法——归并排序_赚钱去流浪的博客-CSDN博客

代码

import java.util.Scanner;

/**
 * @description:
 * @author: gyj
 * @date: 2022/8/29 22:04
 */
public class Main {
  public static Long num;
  public static int[] arr;
  public static int[] brr = new int[500050];
  public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);

    while (sc.hasNext()) {
      int n = sc.nextInt();
      arr = new int[n];
      if (n==0 || n>=500000){
        break;
      }
      num = 0l;
      for (int i = 0; i < arr.length; i++) {
        arr[i] = sc.nextInt();
      }
      mergeSort(arr, 0,n-1);
      System.out.println(num);
      continue;
    }
  }

  public static void merge(int a[],int start,int mid,int end) {
    int i=start,j=mid+1,k=start;
    while(i<=mid&&j<=end) {
      if(a[i]<=a[j]) {
        brr[k++]=a[i++];
      }
      else {
        num+=j-k;
        brr[k++]=a[j++];
      }
    }
    while(i<=mid) {
      brr[k++]=a[i++];
    }
    while(j<=end) {
      brr[k++]=a[j++];
    }
    for(i=start;i<=end;i++,k++) {
      a[i]=brr[i];
    }
  }
  public static void mergeSort(int a[],int start,int end) {
    if(start<end) {
      int mid=(start+end)/2;
      mergeSort(a,start,mid);
      mergeSort(a,mid+1,end);
      merge(a,start,mid,end);
    }
  }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

赚钱去流浪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值