Sword51——数组中的逆序对

Sword51——数组中的逆序对

方法1——归并排序

  • 思路:归并排序思想,将数组进行划分为左右子数组,并且保证子数组其中是有序的
    • 假设只剩下最后两组元素left和right时,当left[i]大于right[j]时,又因为left为有序的,因此left数组后续元素都将大于right[j],将其填入nums原数组,并统计新增的逆序对个数
    • 此处并没有真正将数组划分左右子数组,只是使用一个tmp进行存储,再定义左右子数组的首个元素的起始坐标,以达到划分的目的
  • 特殊情况与临界分析:无
  • 终止条件:无
  • 步骤:
    • 定义全局nums数组、tmp临时数组(模拟左右子数组的划分)
    • 初始化nums
    • 初始化全局变量nums、tmp
    • 进行归并
    • 归并方法(划分 + 合并)
      • 参数:原数组(已为全局变量可不传递)、起始坐标、终止坐标
      • 终止条件:当start大于end时,此时子数组长度为1停止划分,返回新增逆序对为0
      • 获取中间元素下标
      • 递归划分,并统计结果(等于其左半数组与mid的结果、加上其右半数组与mid的结果)
      • 合并阶段,记录当前左右子数组的首部元素(start、及mid + 1)
      • for循环将nums元素复制到tmp中,从start到end
        • 通过tmp数组,加上左右子数组的首部元素下标,达到划分数组的目的
      • for循环从start开始,直到end
        • 主要分为四种情况
        • 1)当左指针left已到mid + 1时,左侧数组已经合并完成,此时不会再出现逆序对
          • 将tmp的右指针right对应元素填入nums当前下标,并且j后移
        • 2)3)当right为end+ 1(右侧数组已经合并完成)、或tmp中left位置比right位置要小
          • 将tmp的左指针left对应元素填入nums当前下标,并且i后移
        • 4)否则(即tmp中left位置比right位置要大)
          • 将tmp的右指针right对应元素填入nums当前下标,并且j后移
          • 只有此时才能统计逆序对,新增逆序对个数为mid - 左指针left + 1
      • 返回结果res
	// 定义全局nums数组、tmp临时数组
	int[] nums, tmp;
	public int reversePairs(int[] nums) {
        // 初始化全局变量
        this.nums = nums;
        tmp = new int[nums.length];
        // 进行归并
        return mergeSort(0, nums.length - 1);
    }
	// 归并方法
	private int mergeSort(int start, int end) {
        // 终止条件
        if (start >= end) {
            return 0;
        }
        // 获取中间元素对应下标
        int mid = start + (end - start)/2;
        // 递归划分
        int res = mergeSort(start, mid) + mergeSort(mid + 1, end);
        // 合并阶段
        int left = start, right = mid + 1;
        // for循环
        for (int i = start; i <= end; i++) {
            tmp[i] = nums[i];
        }
        // for循环
        for (int i = start; i <= end; i++) {
            // 四种情况
            // 1)当左子数组已经处理完毕,即左指针已达mid + 1
            if (left == mid + 1) {
                // 将右子数组元素直接加入nums,右指针后移一位
                nums[i] = tmp[right++];
            // 2)当右子数组已经处理完毕,即右指针已达end + 1
            // 3)当左子数组left元素小于等于右子数组right元素
            } else if (right == end + 1 || tmp[left] <= tmp[right]) {
                // 将左子数组元素直接加入nums,左指针后移一位
                nums[i] = tmp[left++];
            // 4)当左子数组left元素大于右子数组right元素
            } else {
                // 将右子数组元素直接加入nums,右指针后移一位
                nums[i] = tmp[right++];
                // 只有此时才能统计逆序对
                // 此时左子数组的所有元素都大于右子数组j元素
                // 此时可形成逆序对的数量为mid + 1 - left;
                res += mid + 1 - left;
            }
        }
        // 返回结果
        return res;
    }

方法1——归并排序

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值