分治算法

分治算法字面意思就是将一个复杂的数据进行分开计算,分治 的策略就是: 一个分治法将规模为n的问题分成k个规模为n/m的子问题去解。设分解阀值n0=1,且adhoc解规模为1的问题耗费1个单位时间。再设将原问题分解为k个子问题以及用merge将k个子问题的解合并为原问题的解需用f(n)个单位时间。用T(n)表示该分治法解规模为|P|=n的问题所需的计算时间,则有:

T(n)= k T(n/m)+f(n)

通过迭代法求得方程的解:

递归方程及其解只给出n等于m的方幂时T(n)的值,但是如果认为T(n)足够平滑,那么由n等于m的方幂时T(n)的值可以估计T(n)的增长速度。通常假定T(n)是单调上升的,从而当                  mi≤n<mi+1时,T(mi)≤T(n)<T(mi+1)。 

可用分治法求解一些经典问题例如:(可自行百度)
(1)二分搜索
(2)大整数乘法
(3)Strassen矩阵乘法
(4)棋盘覆盖
(5)合并排序
(6)快速排序
(7)线性时间选择
(8)最接近点对问题
(9)循环赛日程表
(10)汉诺塔

Paste_Image.png

那么分治算法到底是怎么分治呢?下面举个简单的例子:
比如:
f(0)=1
f(1)=8
f(n)=f(n-1)+f(n-2)
那么如果我们要求f(80)直接就可以分成f(79)+f(78),然后f(79)和f(78)继续往下一直分直接分解至f(1)+f(0)为止.

下面我们来举个例子算下,比如说有支股票从第0天到16天每天的股价分别为以下:
100,113,110,85,105,102,86,63,81,101,94,106,101,79,94,90,97
然后我们需要求出从哪天买入哪天卖出能够挣钱最多,这里我们有两种方法可以求得,第一种暴力求解,第二种使用分治法。
那么暴力求解怎么求得呢,下面我们用代码实现下
暴力求解

 int[] priceArray = { 100, 113, 110, 85, 105, 102, 86, 63, 81, 101, 94, 106, 101, 79, 94, 90, 97 };
            int[] priceFluctationArray = new int[priceArray.Length - 1];//价格从第0天到第16天内波动的数组
            //求出价格波动的数值
            for (int i = 1; i < priceArray.Length; i++)
            {
                priceFluctationArray[i - 1] = priceArray[i] - priceArray[i - 1];
            }
            int total = priceFluctationArray[0];//默认波动数组的第一个元素是最大数组
            int startIndex = 0;
            int endIndex=0;
            for (int i = 0; i < priceFluctationArray.Length; i++)
            {
                //取得以i为子数组起点的所有子数组
                for (int j = i; j < priceFluctationArray.Length; j++)
                {
                    int totalTemp = 0;//临时 最大数组的和
                    for (int index = i; index < j+1; index++)
                    {
                        totalTemp += priceFluctationArray[index];
                    }
                    if (totalTemp > total)
                    {
                        total = totalTemp;
                        startIndex = i;
                        endIndex = j;
                    }
                }
            }
            Console.WriteLine("购买日期是第" + startIndex+"天,出售是第"+ (endIndex+1)+"天最能挣钱,总共挣"+total);

输出结果

Paste_Image.png

那么下面我们来看看分治算法怎么实现的。
比如我们有一个数组,要求到一个最大子数组,从low到high大小,那么我们直接取一个中间的数值mid,然后这个数组就分成了[low,mid] [mid+1,hight],这个时候就有三种情况
(1)我们需要的值在低区间[low,mid]里面
(2)我们需要的值在高区间[mid+1,hight]里面
(3)我们需要的值位于低区间和高区间之间
Paste_Image.png

这里面我们就将问题分成了小问题去解决,下面我们来看看代码怎么实现
Paste_Image.png

分治算法求解

     //最大子数组的结构体
        struct SubArray
        {
            public int startIndex;//开始索引
            public int endIndex;//结束索引
            public int total;//和
        }
        static void Main(string[] args)
        {
            int[] priceArray = { 100, 113, 110, 85, 105, 102, 86, 63, 81, 101, 94, 106, 101, 79, 94, 90, 97 };
            int[] pf = new int[priceArray.Length - 1];//价格波动的数组
            for (int i = 1; i < priceArray.Length; i++)
            {
                pf[i - 1] = priceArray[i] - priceArray[i - 1];
            }

            SubArray subArray = GetMaxSubArray(0, pf.Length - 1, pf);

            Console.WriteLine("我们在第" + subArray.startIndex + "天买入, 在第" + (subArray.endIndex + 1) + "天卖出" + ",能挣钱" + subArray.total);
            Console.ReadKey();
        }

        static SubArray GetMaxSubArray(int low, int high, int[] array)//这个方法是用来取得array 这个数组 从low到high之间的最大子数组
        {
            //分解的终止的条件
            if (low == high)
            {
                SubArray subarray;
                subarray.startIndex = low;
                subarray.endIndex = high;
                subarray.total = array[low];
                return subarray;
            }

            int mid = (low + high) / 2; // 低区间 [low,mid]  高区间[mid=1,high]

            SubArray subArray1 = GetMaxSubArray(low, mid, array);

            SubArray subArray2 = GetMaxSubArray(mid + 1, high, array);

            //从【low,mid】找到最大子数组[i,mid] 需要的最大子数组位于低区间
            int total1 = array[mid];
            int startIndex = mid;
            int totalTemp = 0;
            for (int i = mid; i >= low; i--)
            {
                totalTemp += array[i];
                if (totalTemp > total1)
                {
                    total1 = totalTemp;
                    startIndex = i;
                }
            }
            //从【mid+1,high】找到最大子数组[mid+1,j]  需要的最大子数组位于高区间
            int total2 = array[mid + 1];
            int endIndex = mid + 1;
            totalTemp = 0;
            for (int j = mid + 1; j <= high; j++)
            {
                totalTemp += array[j];
                if (totalTemp > total2)
                {
                    total2 = totalTemp;
                    endIndex = j;
                }
            }
            //需要的最大子数组位于高区间和低区间之间
            SubArray subArray3;
            subArray3.startIndex = startIndex;
            subArray3.endIndex = endIndex;
            subArray3.total = total1 + total2;
            //判断三个区间的三个和哪个大。需要的最大子数组在哪个区间里面
            if (subArray1.total >= subArray2.total && subArray1.total >= subArray3.total)
            {
                return subArray1;
            }
            else if (subArray2.total >= subArray1.total && subArray2.total >= subArray3.total)
            {
                return subArray2;
            }
            else
            {
                return subArray3;
            }

        }

输出结果


shuc
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,384评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,845评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,148评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,640评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,731评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,712评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,703评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,473评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,915评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,227评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,384评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,063评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,706评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,302评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,531评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,321评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,248评论 2 352

推荐阅读更多精彩内容