15算法思想之分治算法

1. 分治算法思想

  • 分治算法(divide and conquer)的核心思想其实就是四个字,分而治之,也就是将原问题划分为n个规模较小,并且结构与原问题相似的子问题,递归的解决这些子问题,然后再合并其结果,就得到原问题的解。
  • 分治和递归的区别:分治是一种处理问题的思想,递归是一种编程技巧。实际上分治算法一般都比较适合用递归来实现。分治算法的递归实现中,每一层递归都会涉及这样三个操作:
    • (1)分解:将原问题分解成一系列子问题;
    • (2)解决:递归的求解各个子问题,若子问题足够小,则直接求解
    • (3)合并:将子问题的结果合并成原问题
  • 分治算法能解决的问题,一般需要满足以下几个条件:
    • (1)原问题与分解的小问题具有相同的模式
    • (2)原问题分解成的子问题可以独立求解,子问题之间没有相关性(这一点是分治算法和动态规划明显的区别)
    • (3)具有分解终止条件,就是当问题足够小时,可以直接求解
    • (4)可以将子问题合并成原问题,而且这个合并操作的复杂度不能太高(否则就起不到减小算法时间复杂的效果了)

2. 分治算法应用举例

  • (1)排序算法中的有序度、逆序度的计算(假设我们有 n 个数据,我们期望数据从小到大排列,那完全有序的数据的有序度就是 n(n-1)/2,逆序度等于 0;相反,倒序排列的数据的有序度就是 0,逆序度是 n(n-1)/2。除了这两种极端情况外,我们通过计算有序对或者逆序对的个数,来表示数据的有序度或逆序度。),即编程求出一组数据的有序对个数和逆序对个数。
    • 法一、暴力求解:拿每个数字分别和它后面的数字进行对比,记录下逆序对的个数,然后将每个数字的逆序对个数求和,这样可以得出逆序对的个数(有序对个数求解过程类似)
      • 算法的时间复杂度:O(n^2)
      • 算法的空间复杂度:O(1)
    • 法二、使用分治算法,利用归并排序的思路
      • 算法时间复杂度:O(n*lgn)
      • 算法空间复杂度:O(n)
  • class Solution{
        private static int num = 0;    //定义一个类变量,记录逆序对的值
    
        public int countReverse(int[] a){
            num = 0;
            if(a.length == 0) return -1;
            mergeSortCounting(a, 0, a.length-1)
            return num;
        };
        
        public void mergeSortCounting(int[] a, int low, int high){
            if(p>=q) return;
            int mid = (low + high)/2;
            mergeSortCounting(a, low, mid);
            mergeSortCOunting(a, mid+1, high);
            merge(a, low, mid, high);
        };
    
        public void merge(int[] a, int low, int mid, int high){
            
            int i = low, j = mid+1, tempi = 0;
            int[] temp = new int[high - low + 1];   //用于保存待合并的两个数组
            while(i<=mid && j <= high){
                if(a[i]<=a[j]){                    //合并数组
                    temp[tempi++] = a[i++]          
                }else{
                    temp[tempi++] = a[j++];        //右侧数组中的值小于左侧数组,则需要更新num值,并且因为左侧数组是有序的,所以左侧数组a[i]后的其余值全要大于a[j]
                    num += mid-i+1;    
                }
            }
            while(i<=mid){                        //处理剩下的
                temp[tempi++] = a[i++];            
            }
            while(j<=high){                        //处理剩下的
                temp[tempi++] = a[j++];
            }
            for(int m = 0; m<high-low +1; m++){    //将temp数组的值拷贝回a数组中,a数组成为一个有序数组
                a[m] = temp[m];
            }
        };
    }

     

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值