数据结构与算法-分治算法

分治算法一般用递归来实现,分治算法是一种处理问题的思想,递归是一种编程技巧,在分治算法的递归实现中,每一层递归都会涉及这三个操作:

1、分解:将原问题分解成一系列子问题;

2、解决:递归求解各个子问题,若子问题足够小,则直接求解;

3、合并:将子问题的结果合并成原问题。

满足下面几个条件,则可以使用分治算法:

1、原问题与分解成的小问题具有相同的模式;

2、原问题分解成的子问题可以独立求解,子问题之间没有相关性;

3、具有分解终止条件,也就是说,当问题足够小时,可以直接求解;

4、可以将子问题合并成原问题,而且这个合并操作的复杂度不能太高,否则起不到减小算法总体复杂度的效果。

归并排序就是用了分治算法思想,接下来用分治算法求解一组数组的逆序对。逆序对:一组数据中,前面的数比后面大,那么这两个数就是一对逆序对,比如[4,2,3,5],4比2大,4比3大,所以逆序对为2,有序对=总对数-逆序对,总对数为n(n-1)/2。代码如下:

public int num = 0;

    public int count(int[] a) {
        mergeSortCounting(a, 0, a.length-1);
        return num;
    }

    private void mergeSortCounting(int[] a, int start, int end) {
        if(start >= end) {
            return;
        }

        int middle = (start+end)/2;
        mergeSortCounting(a, start, middle);
        mergeSortCounting(a, middle+1, end);
        merge(a, start, middle, end);
    }

    private void merge(int[] a, int start, int middle, int end) {
        int left = start, right = middle+1;
        int[] temp = new int[end-start+1];
        int index = 0;
        while(left <= middle && right <= end) {
            if(a[left] <= a[right]) {
                temp[index++] = a[left++];
            } else {
                num += middle-left+1;
                temp[index++] = a[right++];
            }
        }

        while(left <= middle) {
            temp[index++] = a[left++];
        }

        while(right <= end) {
            temp[index++] = a[right++];
        }

        for(int i = 0; i < end-start+1; i++) {
            a[start+i] = temp[i];
        }
    }

leetcode53题代码

/**
     * leetcode53
     * 给定一个整数数组(有正数有负数),找出总和最大的连续数列,并返回总和。
     *
     * 示例:
     * 输入: [-2,1,-3,4,-1,2,1,-5,4]
     * 输出: 6
     * 解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
     *
     * @param nums
     * @return
     */

    public int maxSubArray(int[] nums) {
        int maxNum = nums[0];
        for(int i = 0; i < nums.length; i++) {
            int currentMax = nums[i];
            maxNum = nums[i] >= maxNum ? nums[i] : maxNum;
            for(int j = i + 1; j < nums.length; j++) {
                currentMax = nums[j] + currentMax;
                maxNum = currentMax >= maxNum ? currentMax : maxNum;
            }
        }
        return maxNum;
    }

    /**
     * 分治算法
     * @param nums
     * @return
     */
    public int maxSubArray01(int[] nums) {
        return dacMaxSubArray(nums, 0, nums.length-1);
    }

    private int dacMaxSubArray(int[] nums, int left, int right) {
        if(left == right) {
            return nums[left];
        }

        int middle = (left+right)/2;
        int leftMax = dacMaxSubArray(nums, left, middle);
        int rightMax = dacMaxSubArray(nums, middle+1, right);

        int middleToLeftMax = Integer.MIN_VALUE;
        int middleToLeftCurrentMax = 0;
        for(int i = middle; i >= left; i--) {
            middleToLeftCurrentMax += nums[i];
            middleToLeftMax = Math.max(middleToLeftCurrentMax, middleToLeftMax);
        }

        int middleToRightMax = Integer.MIN_VALUE;
        int middleToRightCurrentMax = 0;
        for(int j = middle+1; j <= right; j++) {
            middleToRightCurrentMax += nums[j];
            middleToRightMax = Math.max(middleToRightCurrentMax, middleToRightMax);
        }

        int middleMax = middleToLeftMax + middleToRightMax;
        return Math.max(middleMax, Math.max(leftMax, rightMax));
    }

    /**
     * 动态规划
     * @param nums
     * @return
     */
    public int maxSubArray02(int[] nums) {
        int max = nums[0];
        int sum = nums[0];
        for(int i = 1; i < nums.length; i++) {
            if(sum < 0) {
                sum = nums[i];
            } else {
                sum += nums[i];
            }
            max = Math.max(sum, max);
        }
        return max;
    }

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值