分治策略

分治策略的基本思想是,将一个问题分解成若干个子问题,这样不断的递归分解,直到分解的足够小时直接分解。经典的分治策略实现有归并排序,快速排序

步骤

  • 分解:将问题分解为一些子问题,子问题的形式与原问题的方式一致,只是规模更小。
  • 解决:递归的分解出子问题,如果子问题的规模足够小,则停止递归直接求解。
  • 合并:将子问题的解组合成原问题的解

举例说明

  • 排序中比较暴力的方法就是选择排序和冒泡排序,拿选择排序来说,每一次遍历选择数组中的最大值,需要遍历n次,也就是将排序分为n层来处理,每一层的时间复杂度为o(n),总时间复杂度为O(n^2)
  • 然而对比归并排序和快排,都是将一个问题分为两个子问题来解决,以此类推总共分为logn层(可以脑部二叉树的结构),每一层的时间复杂度为o(n),总时间复杂度为O(nlogn),对比可以得知分治策略优化的是层数,可以想成将一个nn矩阵的结构优化成了二叉树的结构,明显缩短时间
    在这里插入图片描述

例题1:求解最大子数组

  • 题目给出一个数组,求给出数组的子数组和最大值
  • 分析:定义一个分界点mid,最大子数组可能存在三种情况:1.子数组在mid左边。2.子数组在mid右边。3.子数组包含mid。
  • 根据分治策略的解决步骤:1.分解,将这个问题中经过mid点的情况处理掉,然后将数组由mid为 分界点分为left和right两个子数组。2.解决,当数组分解足够小,即子数组中只存在一个元素时,返回该元素.3.合并,取left数组最大子数组,right数组最大子数组,当前最大子数组中的最大值返回。
  • 代码
    public static int MaxSubArray(int[] array,int High,int Mid,int Low){
        //当问题分解足够小时,解决问题
        if(High==Low){
            return array[High];
        }
        //初始化
        int right_sum=array[Mid];
        int left_sum=array[Mid-1];
        int sum=0;
        //当子数组包含mid时,取最大子数组
        for(int i=Mid-1;i>=Low;i--){
            sum=sum+array[i];
            if(sum>left_sum){
                left_sum=sum;
            }
        }
        sum=0;
        for(int i=Mid;i<=High;i++){
            sum=sum+array[i];
            if(sum>right_sum){
                right_sum=sum;
            }
        }
        //分解
        int Max_left=MaxSubArray(array,Mid-1,(Mid-Low)/2+Low,Low);
        int Max_right=MaxSubArray(array,High,(High-Mid+1)/2+Mid,Mid);
        int Max_center= right_sum+left_sum;
        if(Max_center>Max_left && Max_center>Max_right){
            return Max_center;
        }else if(Max_left>Max_right){
            return Max_left;
        }else {
            return Max_right;
        }
    }

例题2:归并排序

  • 分解:将数组分解成只有一个元素的数组(元素只有一个为有序数组)
  • 回溯归并:合并两个有序子数组
  • 代码
    public static void MergeSort(int[] array,int High,int Mid,int Low){
        //分解成最小单位时返回
        if(High==Low){
            return;
        }
        //分解成两个子元素
        MergeSort(array,High,(High+Mid+1)/2,Mid+1);
        MergeSort(array,Mid,(Mid+Low)/2,Low);
        //创建两个数组存储当前数组的left和right部分
        int m=Mid-Low+1;
        int n=High-Mid;
        int[] Left=new int[m];
        int[] Right=new int[n];
        int j=0,k=0;
        for(int i=0;i<=Mid-Low;i++){
            Left[i]=array[Low+i];
        }
        for(int i=0;i<=High-Mid-1;i++){
            Right[i]=array[Mid+1+i];
        }
        //合并两个有序数组
        for(int i=Low;i<=High;i++){
            if(k>=n || (j<m && Left[j]<=Right[k])){
                array[i]=Left[j];
                j++;
            }else{
                array[i]=Right[k];
                k++;
            }
        }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值