左神算法笔记-归并排序

65 阅读1分钟

前提

ps:通过此公式分析递归函数的时间复杂度,要求所有子问题规模相同的递归才能用master公式。

T(n)=aT(n/b)+O(nc)T(n) = a * T(n/b) + O(n^c) 解释:

  • 我要处理数据量为n的问题,调用子过程规模为原来的1/b,调用了a次。
  • O(nc) O(n^c)代表除了递归的代码,其他代码的时间复杂度;

有三种情况

  • 如果log(b,a)<clog(b,a) < c,复杂度为:O(nc)O(n^c)
  • 如果log(b,a)>clog(b,a) > c,复杂度为:O(nlog(b,a))O(n^log(b,a))
  • 如果log(b,a)==clog(b,a) == c,复杂度为:O(nclogn)O(n^c * logn)
  • 补充 T(n)=2T(n/2)+O(nlogn) T(n) = 2*T(n/2) + O(n*logn),时间复杂度是O(n((logn)的平方))O(n * ((logn)的平方)),证明过程比较复杂,记住即可

拿归并排序来讲: T(N)=2T(N/2)+O(N)T(N) =2 * T(N/2) + O(N),即归并排序复杂度:O(NlogN)O(N*logN)

归并排序代码

class Solution {
    public int[] sortArray(int[] nums) {
        if (nums.length <= 1) {
            return nums;
        }
        // 归并排序,
        sort(nums, 0, nums.length - 1);
        return nums;
    }

    public void sort(int[] nums, int l, int r) {
        // 左右边界一致,无需排序返回
        if (l == r) {
            return;
        }
        int m = (r + l) / 2;
        // 排左边
        sort(nums, l, m);
        // 排右边
        sort(nums, m + 1, r);
        // 左右两边排好序完,归并
        merge(nums, l, m, r);
    }

    public void merge(int[] nums, int l, int m, int r) {
        int i = l, a = l, b = m + 1;
        // 注意此处,辅助数组的长度是r的长度+1,避免每次递归都分配大数组。超时
        int[] temp = new int[r + 1];
        while (a <= m && b <= r) {
            temp[i++] = nums[a] <= nums[b] ? nums[a++] : nums[b++];
        }
        while (a <= m) {
            temp[i++] = nums[a++];
        }
        while (b <= r) {
            temp[i++] = nums[b++];
        }
        for (i = l; i <= r; i++) {
            nums[i] = temp[i];
        }
    }
}