算法(C#版)分治算法

分治算法

分治策略是:对于一个规模为n的问题,若该问题可以容易地解决(比如说规模n较小)则直接解决,否则将其分解为k个规模较小的子问题,这些子问题互相独立且与原问题形式相同,递归地解这些子问题,然后将各子问题的解合并得到原问题的解。这种算法设计策略叫做分治法。

可使用分治法求解的一些经典问题:

(1)二分搜索

(2)大整数乘法

(3)Strassen矩阵乘法

(4)棋盘覆盖

(5)合并排序

(6)快速排序

(7)线性时间选择

(8)最接近点对问题

(9)循环赛日程表

(10)汉诺塔

分治算法 - 最大子数组问题

天数

0

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

价格

100

113

110

85

105

102

86

63

81

101

94

106

101

79

94

90

97

变化

 

13

-3

-25

20

-3

-16

-23

18

20

-7

12

-5

-22

15

-4

7

股票问题

1,暴力求解

2,分治法

暴力求解的方法实现

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace 最大子数组问题_暴力求解
{
    class Program
    {
        static void Main(string[] args)
        {
            int[] priceArray = { 100, 113, 110, 85, 105, 102, 86, 63, 101, 94, 106, 101, 79, 94, 90, 97 };
            int[] priceFluctuationArray = new int[priceArray.Length - 1];//价格波动的数组
            for(int i = 1; i < priceArray.Length; i++)
            {
                priceFluctuationArray[i - 1] = priceArray[i] - priceArray[i - 1];
            }

            int total = priceFluctuationArray[0];//默认数组的第一个元素是最大子数组
            int startIndex = 0;
            int endIndex = 0;

            for(int i = 0; i < priceFluctuationArray.Length; i++)
            {
                //取得以i为子数组起点的 所有子数组
                for(int j = i; j < priceFluctuationArray.Length; j++)
                {
                    //由ij就确定了一个子数组
                    int totalTemp = 0;//临时最大子数组的和
                    for(int index =i;index < j + 1; index++)
                    {
                        totalTemp += priceFluctuationArray[index];
                    }
                    if (totalTemp > total)
                    {
                        total = totalTemp;
                        startIndex = i;
                        endIndex = j;
                    }

                }
            }
            Console.WriteLine("startindex:" + startIndex);
            Console.WriteLine("endindex:" + endIndex);
            Console.WriteLine("购买时期是第" + startIndex + "天 出售是第" + (endIndex + 1)+"天");
            Console.ReadKey();
        }
    }
}

分治法的实现

第三种情况遍历高低区间,找到最大的i和j

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace 最大子数组问题_分治法
{
    class Program
    {
        /// <summary>
        /// 最大子数组结构体
        /// </summary>
        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, 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);
            Console.WriteLine(subArray.endIndex);
            Console.WriteLine(subArray.total);
            Console.WriteLine("购买时期是第" + subArray.startIndex + "天 出售是第" + (subArray.endIndex + 1) + "天");
            Console.ReadKey();

        }

        /// <summary>
        /// 这方法是取得array 这个数组 从low到high之间的最大子数组
        /// </summary>
        /// <param name="low"></param>
        /// <param name="high"></param>
        /// <param name="array"></param>
        static SubArray GetMaxSubArray(int low, int high, int[] array)
        {
            if(low == high)
            {
                SubArray subArray;
                subArray.startIndex = low;
                subArray.endIndex = high;
                subArray.total = array[low];
                return subArray;
            }

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

            SubArray s1 = GetMaxSubArray(low, mid, array);
            SubArray s2 = 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 s3;
            s3.startIndex = startIndex;
            s3.endIndex = endIndex;
            s3.total = total1 + total2;

            if (s1.total >= s2.total && s1.total >= s3.total)
                return s1;
            else if (s2.total >= s1.total && s2.total >= s3.total)
                return s2;
            else
                return s3;
        }
    }
}

猜你喜欢

转载自blog.csdn.net/kouzhuanjing1849/article/details/88839450
今日推荐