一次性弄懂到底什么叫做分治思想(含有大量经典例题,附带详细解析)

期末了,通过写博客的方式复习一下算法,把自己知道的全部写出来

分治:分而治之,把一个复杂的问题分解成很多规模较小的子问题,然后解决这些子问题,把解决的子问题合并起来,大问题就解决了

但是我们应该在什么时候用分治呢?这个问题也困扰了我很久,做题的时候就不知道用什么算法

能用分治法的基本特征:

1.问题缩小到一定规模容易解决

2.分解成的子问题是相同种类的子问题,即该问题具有最优子结构性质

3.分解而成的小问题在解决之后要可以合并

4.子问题是相互独立的,即子问题之间没有公共的子问题

第一条大多数问题都可以满足

第二条的大多数问题也可以满足,反应的是递归的思想

第三条:这个是能分治的关键,解决子问题之后如果不能合并从而解决大问题的话,那凉凉,如果满足一,二,不满足三,即具有最优子结构的话,可以考虑贪心或者dp

第四条:如果不满足第四条的话,也可以用分治,但是在分治的过程中,有大量的重复子问题被多次的计算,拖慢了算法效率,这样的问题可以考虑dp(大量重复子问题)

了解了什么问题可以采用分治,那么分治到达怎么用?步骤是什么呢

三个步骤:

1.分解成很多子问题

2.解决这些子问题

3.将解决的子问题合并从而解决整个大问题

化成一颗问题树的话,最底下的就是很多小问题,最上面的就是要解决的大问题,自底向上的方式求解问题

说的再多不如看经典的样例,更好的体会分治的思想

样例1:二分查找

条件:数组有序,假设是升序数组

虽然二分很容易,但是我还是要具体从算法思想分治的方向分析一下

现在我们要在一个有序的升序数组里面查找一个数x有没有

暴力的做法就是拿跟数组里面每个数比较一下,有的话就返回下标,这个是大问题

仔细想一下,就知道这个大问题是由很多小问题组成的,小问题:在数组的一部分里面找x

那么我们可以把数组分成很多部分,在很多部分里面找x,如果在这些部分里面没有找到x,那么把这些子问题合并起来,就是大数组里面没有x,否则就是有x

这个真的很好的反应了分治的思想,先分解成很多小问题,解决这些小问题,把解决的小问题合并起来,大问题就解决了,二分具体的做法我就不多说了,都知道,贴个代码

#include<string.h>
#include<stdio.h>
int k;
int binarysearch(int a[],int x,int low,int high)//a表示需要二分的有序数组(升序),x表示需要查找的数字,low,high表示高低位
{
    if(low>high)
    {
        return -1;//没有找到
    }
    int mid=(low+high)/2;
    if(x==a[mid])//找到x
    {
        k=mid;
        return x;
    }
    else if(x>a[mid]) //x在后半部分
    {
        binarysearch(a,x,mid+1,high);//在后半部分继续二分查找
    }
    else//x在前半部分
    {
        binarysearch(a,x,low,mid-1);
    }
}
int main()
{
    int a[10]={
    1,2,3,4,5,6,7,8,9,10};
    printf("请输入需要查找的正数字:\n");
    int x;
    scanf("%d",&x);
    int r=binarysearch(a,x,0,9);
    if(r==-1)
    {
        printf("没有查到\n");
    }
    else
    {
        printf("查到了,在数列的第%d个位置上\n",k+1);
    }
    return 0;
}

经典样例二:全排列问题

有1,2,3,4个数,问你有多少种排列方法,输出来

仔细想想,采用分治的话,我们就要把大问题分解成很多的子问题,大问题是所有的排列方法

那么我们分解得到的小问题就是以1开头的排列,以2开头的排列,以3开头的排列,以4开头的排列

现在这些问题有能继续分解,比如以1开头的排列中,只确定了1的位置,没有确定2,3,4的位置,把2

3,4三个又看成大问题继续分解,2做第二个,3做第二个,或者4做第二个

一直分解下去,直到分解成的子问题只有一个数字的时候,不再分解

因为1个数字肯定只有一种排列方式啊,现在我们分解成了很多的小问题,解决一个小问题就合并,合并成

一个大点的问题,合并之后这个大点的问题也解决了,再将这些大点的问题合并成一个更大的问题,那么这

个更大点的问题也解决了,直到最大的问题解决为止

这个就是用分治的思想解决全排列问题,我主要想分析的是分治的思想者全排列问题上是怎么用的,不想分析具体全排列的做法,因为我觉得思想比方法更重要,在解题的时候深有体会,因为又的时候没有题是你做过的原题,全排列问题的具体做法参考我的这篇博客:https://www.cnblogs.com/yinbiao/p/8684313.html,也贴一下代码

#include<string.h>
#include<stdio.h>
int k=0;
char a[100];
long long count=0;//全排列个数的计数
void s(char a[],int i,int k)//将第i个字符和第k个字符交换
{
    char t=a[i];
    a[i]=a[k];
    a[k]=t;
}
void f(char a[],int k,int n)
{
    if(k==n-1)//深度控制,此时框里面只有一个字符了,所以只有一种情况,所以输出
    {
       puts(a);
       count++;
    }
    int i;
    for(i=k;i<n;i++)
    {
        s(a,i,k);
        f(a,k+1,n);
        s(a,i,k);
  • 158
    点赞
  • 384
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值