算法 - 分治与回溯

本文介绍了分治和回溯两种算法。分治算法通过分解问题、解决子问题和合并解来解决问题,如在计算数组逆序对时使用归并排序。回溯算法是一种试错的搜索过程,用于在所有可能的解中找到正确答案,例如在N皇后问题中的应用。
摘要由CSDN通过智能技术生成

文章放置于:https://github.com/zgkaii/CS-Notes-Kz,欢迎批评指正!

分治

基本概念

分治算法(divide and conquer)和核心思想正如其字面含义,分而治之,就是把一个复杂问题分成两个或者更多的相同和相似的问题,直到最后问题可以简单的直接求解,原问题的解即是子问题解的合并。

这个定义看起来类似递归的定义,区别在于分治算法是一种处理问题的思想,而递归是一种编程技巧。实际上,分治算法一般比较适合用递归来实现,当然也可以用迭代来实现,这也是区别之一。递归算法从本质上来就是分治算法,无非就是有些问题递归需要将原问题分解成多个子问题,而有的只需要分解成一个子问题,前者为分治,后者即为递归。

分治算法能解决的问题一般满足下面几个条件:

  • 分解(Divide):将原问题分解成若干个子问题。
  • 解决(Conquer):分解的子问题足够小并可以独立求解的话,就直接求解。
  • 合并(Merge):将子问题的解合并,形成原问题的解。(这个合并操作的复杂度不易过高)

分治算法一般体现在归并排序快速排序里面。

经典举例

剑指 Offer 51. 数组中的逆序对为例,如果数组中的两个数字,前面一个数字大于后面的数字,则这两个数字组成一个逆序对。

例如数组[7,5,6,4],其逆序对有(7,5),(7,6),(7,4),(5,4),(6,4),逆序数为3+1+1=5。正如这里罗列的一样,暴力解法即拿每个数字跟它后面的数字比较,统计比它小的数记着kn个元素就有对应的n个逆序数k,然后求这nk之和。这样操作的时间复杂度为O(n2)。有没有更加高效的处理方法呢?

这里,可以采用分治的思想来解决问题。先把数组分成前后两个部分leftPartrightPart,分别计算leftPartrightPart对应逆序对数k1k2,然后再计算 leftPartrightPart 之间的逆序对个数 K3。那么总的逆序数为k1+k2+k3了。这样,通过分治把问题分解成独立子问题直接求解,最后再合并子问题的解。

为保证合并的操作复杂度不高,可以采用归并排序算法来解决。归并排序中有一个非常关键的操作,就是将两个有序的小数组,合并成一个有序的数组。如下图所示,为数组 [7, 3, 2, 6, 0, 1, 5, 4]的归并排序过程。

合并阶段本质上是合并两个排序数组的过程,而每当遇到 左子数组当前元素 > 右子数组当前元素 时,意味着 「左子数组当前元素 至 末尾元素」 与 「右子数组当前元素」 构成了若干 「逆序对」 。

    public int reversePairs(int[] nums) {
   
        if (nums.length < 2) 
            return 0;
        int[] tmp = new int[nums.length];// 临时数组用于归并
        return mergeSort(nums, tmp, 0, nums.length - 1);
    }

    public int mergeSort(int[] nums, int[] tmp, int left, int right) {
   
        // 终止条件,子数组长度为1,停止划分
        if (left >= right) 
            return 0;
        // 递归划分左子数组与右子数组
        int mid = left + right >>> 1;
        int res = mergeSort(nums, tmp, left, mid) + mergeSort(nums, tmp, mid + 1, right);
        //  合并阶段 idx为临时数组的移动指针
        int i = left, j = mid + 1, idx = left, count = 0;
        // 左右两数组都还剩有数字未排序时
        while (i <= mid && j <= right) {
   
            if (nums[i] > nums[j]) {
   
                tmp[idx+&#
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值