python分治法、暴力法、动态规划求最大子数组

《算法导论》第四章后习题4.1-3

交叉点的计算通过20次求两种方法的最小时间差,然后取平均值求得。
以50000个随机元素的列表为例:
暴力法需要约两分钟,分治法需要0.19s,而动态规划只需要0.013s。(单次数据)

import math
import time
import random


def force(profit):
    """
    use forceful method
    :param profit: profit list
    :return: the max profit
    """
    maxprofit = 0
    for i in range(len(profit)):
        for j in range(i + 1, len(profit)):
            if profit[j] - profit[i] > maxprofit:
                maxprofit = profit[j] - profit[i]
    return maxprofit


def fluctuated(profit):
    """
    calculate profit list to fluctuated list
    :param profit: profit list
    :return: fluctuated list
    """
    a = []
    for i in range(len(profit) - 1):
        a.append(profit[i + 1] - profit[i])
    return a


def dp(v):
    """
    calculate profit list to fluctuated list
    :param v: fluctuated list
    :return: the max profit
    """
    add = v[0]
    res = add
    for i in range(1, len(v)):
        if add > 0:
            add += v[i]
        else:
            add = v[i]
        res = max(res, add)
    return res


# class Result:
#     """
#     ans : max sum
#     sub : max subarray
#     low
#     high
#     """
#     ans = 0
#     low = high = 0
#
#     def __init__(self, ans, low, high):
#         self.low = low
#         self.high = high
#         self.ans = ans


def find_cross_subarray(v, low, high):
    """
    find cross subarray
    :param v: volatility list
    :param low: lower-bound
    :param high: upper-bound
    :return: an object includes subarray and max sum
    """
    lsum = -9999999999
    add = 0
    mid = math.floor((low + high) / 2)
    max_right = max_left = 0
    for i in range(mid, low - 1, -1):
        add += v[i]
        if add > lsum:
            lsum = add
            max_left = i
    rsum = -99999999999
    add = 0
    for j in range(mid + 1, high):
        add += v[j]
        if add > rsum:
            rsum = add
            max_right = j
    return lsum + rsum, max_left, max_right


def find_max_sub(v, low, high):
    """
    :param v: a fluctuated list
    :param low: list's lower-bound
    :param high: list's upper-bound
    :return: the max subarray-info
    """

    if high == low:
        return v[low], low, high
    else:
        mid = math.floor((low + high) / 2)
        (left_sum, left_low, left_high) = find_max_sub(v, low, mid)
        (right_sum, right_low, right_high) = find_max_sub(v, mid + 1, high)
        (cross_sum, cross_low, cross_high) = find_cross_subarray(v, low, high)
        # compare
        if left_sum >= right_sum and left_sum >= cross_sum:
            return left_sum, left_low, left_high
        elif right_sum >= left_sum and right_sum >= cross_sum:
            return right_sum, right_low, right_high
        else:
            return cross_sum, cross_low, cross_high

def get_random_list(size, lower, upper):
    """
    generate a random array
    :param size: size
    :param lower: bound
    :param upper: bound
    :return: random array
    """
    arr = []
    i = 0
    while i < size:
        arr.append(random.randint(lower, upper))
        i += 1
    return arr


def exe_time(size, times):
    """
    generate a <size>-length random array,and test two method by <times> times;
    :param size: random array's size
    :param times: execute times
    :return: two methods' time diff
    """
    random_arr = get_random_list(size, 10000, 1000000)
    f_arr = fluctuated(random_arr)
    force_start = time.time()
    for i in range(times):
        force(random_arr)
    force_end = time.time()
    force_last = force_end - force_start
    div_start = time.time()
    for i in range(times):
        find_max_sub(f_arr, 0, len(f_arr) - 2)
    div_end = time.time()
    div_last = div_end - div_start
    # print("Force-last:" + "%s" % force_last)
    # print("div-last:" + "%s" % div_last)
    return abs(div_last - force_last)


def test_intersection(times):
    """
    find two methods' crosspoint
    execute 20 times and calculate the averager
    :return: intersection
    """
    i = 0
    add_times = 0
    while i < 20:
        j = 60
        inter = j
        min_diff = exe_time(j, times)
        while j > 10:
            j -= 1
            diff = exe_time(j, times)
            if diff < min_diff:
                min_diff = diff
                inter = j
            # print("diff:%-30s" % diff, "times:%s" % i)
        print("intersections:", inter)
        add_times += inter
        i += 1
    return add_times / 20


def main():
    print("Average:", test_intersection(70))

    # print(exe_time(10, 10000))
    # RandomArr = get_random_list(50000, 10000, 1000000)
    # FArr = fluctuated(RandomArr)
    # print(RandomArr)
    # t_start = time.time()
    # Max = force(RandomArr)
    # t_end = time.time()
    # print("%-15s" % "Method", "%-15s" % "Result", "Time")
    # print("%-15s" % "Force", "%-15s" % Max, t_end - t_start)
    #
    # t_start = time.time()
    # (res, l, h) = find_max_sub(FArr, 0, len(RandomArr) - 2)
    # t_end = time.time()
    # print("%-15s" % "Div_Recursion", "%-15s" % res, t_end - t_start)
    #
    # t_start = time.time()
    # Max = dp(FArr)
    # t_end = time.time()
    # print("%-15s" % "DP", "%-15s" % Max, t_end - t_start)


if __name__ == '__main__':
    main()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值