左神算法讲堂笔记 01 归并排序和应用 --- 小和问题、逆序数

1、master公式求递归的时间复杂度

T(N) = a*T(N/b) + O(N^d)

  1. log(b,a) > d -> 复杂度为O(N^log(b,a))
  2. log(b,a) = d -> 复杂度为O(N^d * logN)
  3. log(b,a) < d -> 复杂度为O(N^d)

2、归并排序(合并的时候,相等值那么左边先放,就能实现稳定性)

第一步:左边整体有序
第二步:右边整体有序
第三步:左右整合成完全有序(耗费空间o(n))

时间复杂度根据master公式求得 T(n) = 2 * T(n/2) + o(n) = o(N * logN )

3、小和问题

左神算法讲堂笔记 01 归并排序和应用 --- 小和问题、逆序数_第1张图片

解法:

利用归并排序,维护左右部分有序,用下标p1遍历左部分,p2遍历右部分。
在整合左右部分为有序时,可以进行小和的计算。
当arr[ p1 ] < arr[ p2 ] 时,此时产生的小和数为 arr[ p1 ] * ( r - p2 + 1) 。然后把arr [ p1 ]放到帮助数组中, p1++。
否则直接把arr[ p2 ] 放到帮助数组, p2++;

 public int smallSum(int[] arr) {
        if(arr == null || arr.length < 2)
            return 0
        return merge(arr, 0, arr.length - 1);
    }

    public int merge(int[] arr, int l, int r) {
       if(l == r)
           return 0;
        int mid = ((l+r)>>1);
        return merge(arr, l, mid) +merge(arr, mid + 1, r)+ exchange(arr,l,r);
    }

    int exchange(int[] arr, int l, int r) {
        int mid = ((l+r)>>1);
        int p1 = l, p2 = mid+1;
        int arr2[] = new int[r-l+1];
        int index = 0;
        int tmp = 0;
        while (p1 <= mid && p2 <= r) {
            if (arr[p1] < arr[p2]) {
                //右边大
                tmp += arr[p1] * (r - p2 + 1);
                arr2[index++] = arr[p1++];
            }else
                arr2[index++] = arr[p2++];
        }
        while (p1<=mid){
            arr2[index++] = arr[p1++];
        }
        while (p2<=r){
            arr2[index++] = arr[p2++];
        }
        index = 0;
        while (l<=r){
            arr[l++] = arr2[index++];
        }
        return tmp;
    }

4、逆序数问题

求和过程中,当 arr[ p1 ] > arr[ p2 ],res += mid-p1+1

你可能感兴趣的:(算法讲堂)