Fork me on GitHub

算法导论学习笔记 一 分治算法

分治策略是一种常见的算法。在分治策略中,我们递归的求解一个问题,在每层递归中应用如下三个步骤: 1. 分解,将问题分解成规模更小但解决方案相同的子问题 2. 解决,递归的求解子问题,如果子问题足够小则停止递归,直接求解 3. 合并,将子问题的解组合成原问题的解

最大字数组问题

给你一段股市的波动图,找到在什么时候买入,什么时候卖出能获得最大的收益。

暴力破解法

我们很容易的想到一个包里破解法,就是把所有买入,卖出的组合列举出来进行对比,n天中取任意两天作为买入日和卖出日,共有n*(n-1)/2种解法,因此这种解法的时间复杂度是O(n^2)。

问题变换

为了方便我们处理,我们把每个数组的值变为股票的净增量。这个时候,最佳解法就变成了求一个数组的最大字数组:

使用分治策略的求解法

我们可以认为,我们要寻找子数组array[start,end]的最大字数组分三种情况:

  • 最大字数组在左半部分
  • 最大字数组在右半部分
  • 最大字数组起点在左半部分,终点在右半部分

对于前两种情况,我们的求解方式和分解前是相同的,我们需要单独处理第三种情况。

如图:

那么我们给出解这个问题的思路:

FindMaxCrossingSubArray(array,start,end)
	mid=(start+end)/2
	从mid开始向左找,找到以mid为终点的最大字数组为array[max-left,min]
	从mid开始向右找,找到以mid为起点的最大字数组array[min,max-right]
	跨越mid的最大字数组为array[max-left,max-right]
	max-leftchild =FindMaxCrossingSubArray(array,start,mid)
	max-rightchild =FindMaxCrossingSubArray(array,min,end)
	return max-leftchild,max-rightchild,array[max-left,max-right] 3个中的最大字数组

分治算法分析

这种方法我们需要遍历的次数会比n^2少一些,时间复杂度为O(nlgn)

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
public int[] FindRecrusive(int[] array, int low, int high)
{
    Console.WriteLine("low {0}, high {1}", low, high);
 
    if (low == high)
    {
        return new[] { low, high, array[low] };
    }
    int mid = (low + high) / 2;
 
    int leftmaxsum = int.MinValue;
    int currentleftsum = 0;
    int leftmaxlocation = mid;
 
    for (int i = mid; i >= low; i--)
    {
        currentleftsum += array[i];
        if (currentleftsum > leftmaxsum)
        {
            leftmaxsum = currentleftsum;
            leftmaxlocation = i;
        }
    }
 
    int rightmaxsum = 0;
    int currentrightsum = 0;
    int rightmaxlocation = mid;
 
    for (int j = mid + 1; j <= high; j++)
    {
        currentrightsum += array[j];
        if (currentrightsum > rightmaxsum)
        {
            rightmaxsum = currentrightsum;
            rightmaxlocation = j;
        }
    }
 
    int[] result = new[] { leftmaxlocation, rightmaxlocation, leftmaxsum + rightmaxsum };
 
    int[] leftresult = FindRecrusive(array, 0, mid);
 
    if (leftresult[2] > result[2])
    {
        result = leftresult;
    }
 
    int[] rightresult = FindRecrusive(array, mid + 1, high);
    if (rightresult[2] > result[2])
    {
        result = rightresult;
    }
 
    return result;
}

  

自己尝试用C#实现了下,托管在了github

posted @   独上高楼  阅读(784)  评论(2编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· .NET周刊【3月第1期 2025-03-02】
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· [AI/GPT/综述] AI Agent的设计模式综述
点击右上角即可分享
微信分享提示