备战蓝桥杯:两道关于逆序对的问题

题1:给定两个排序后的数组A和B, 其中A的末端有足够的缓冲空间容纳B, 编写一个方法, 将B合并入A并排序

解题思路: 定义指针a和指针b,如果a>=b,a元素等于current元素,指针a左移一位,指标current左移一位,直到a指针或者b指针小于0, 这里考虑到如果数组B整体小于数组A,可能指针a走出了边界,指针b左边的元素全部挪过去,如果是指针b先出了边界,指针a左边的元素不需挪动,因为整体已经有序了,自己可以图画试试
在这里插入图片描述

代码如下

static void mergeSort(int[] A, int[] B) {
     // 待插入元素的位置
     int current = A.length - 1;
     // 数组a待比较元素下标
     int a = A.length - B.length - 1;
     // 数组b待比较元素下标
     int b = B.length - 1;
     while (a >= 0 && b >= 0) {
         if (A[a] >= B[b]) {
             A[current] = A[a];
             a--;
             current--;
         }
         else {
             A[current] = B[b];
             b--;
             current--;
        }
     }
     // 考虑到数组B没走完
     while (b >= 0) {
         A[current] = B[b];
         b--;
         current--;
     }
     Util.printArr(A);
 }

题2:逆序对个数 一个数列, 如果左边的数大, 右边的数小, 侧称这两个数为一个逆序对, 求一个数列有几个逆序对

解题思路1:暴力破解法,依次扫描数组中每个数在它右边的元素并比较, O(n²)
在这里插入图片描述

代码如下

/**
 * @param arr 数组
 * @param l 开始下标
 * @param r 结束下标
 * @param count 逆序对个数(初始化为0)
 * @return 返回逆序对个数
 */
static int topic2(int[] arr, int l, int r, int count) {
        // 边界, 当l走到r的位置, 说明没有需要比较的元素了, 直接返回count
        if (l == r) {
            return count;
        }
        // 不断更新l, i表示向右推进的指针
        int i = l;
        // 往右侧扫描比它小的数
        while (i < r) {
            if (arr[l] > arr[i+1]) // 如果比它小count++
                count++;
            i++;
        }
        return topic2(arr, l + 1, r,count);
    }

解题思路2: 利用归并排序解题, 可以很好的优化时间复杂度, nlogn
在这里插入图片描述
代码如下

	// 辅助空间数组
    static int[] helper;
    // 逆序对个数
    static int niXu = 0;

    private static void mergeSort(int[] arr) {
        helper = new int[arr.length];
        mergeSort(arr,0, arr.length-1);
    }

    private static void mergeSort(int[] arr, int l, int r) {
        if (l < r) {
            int mid = l + ((r - l) >> 1);
            mergeSort(arr,l, mid);
            mergeSort(arr, mid+1, r);
            // 合并
            merge(arr, l, mid, r);
        }
    }

    public static void merge(int[] arr, int l, int mid, int r) {
        //拷贝到辅助空间的相同位置
        System.arraycopy(arr, l, helper, l, r - l + 1);
        // 辅助数组的两个指针
        int left = l, right = mid+1;
        // 原始数组的指针
        int current = l;
        while (left <= mid && right <= r) {
            if (helper[left] <= helper[right]) {
                arr[current++] = helper[left++];
            } else { 
                arr[current++] = helper[right++];
                // 右边小说明有逆序对
                niXu += mid-left+1;
            }
        }
        while (left <= mid) {
            arr[current] = helper[left];
            current++;
            left++;
        }
    }

有什么问题欢迎大佬指正

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值