动态规划算法

1.最大连续乘积子数组

给定一个浮点数数组,任意取出数组中的若干个连续的数相乘,请找出其中乘积最大的子数组。

蛮力轮询:

def max_substring(list_a, length):
    max_result = list_a[0]
    for i in range(length):
        x = 1
        for j in range(i, length):
            x *= list_a[i]
            if x > max_result:
                max_result = x
    return max_result

时间复杂度为O(n^2)

动态规划:

乘积子数组中可能有正数,负数, 也可能有0。

由于负数的存在,可考虑同时找出最大乘积和最小乘积。

假设数组为a[],直接利用动态规划来求解。

状态转移方程:

maxend = max(max(maxend*a[i], minend*a[i]), a[i])

minend = min(max(maxend*a[i], minend*a[i]), a[i])

状态方程初始状态:

maxend = minend = a[0]

def max_substring(list_a, length):
    max_end = min_end = list_a[0]
    for i in range(1, length):
        end1 = max_end*list_a[i]
        end2 = min_end*list_a[i]
        max_end = max(max(end1, end2), list_a[i])
        min_end = min(min(end1, end2), list_a[i])
    max_result = max(list_a[0], max_end)
    return max_result 

时间复杂度为O(n)。

 

2.字符串编辑距离

给定一个源串和目标串,能够对源串进行如下操作:

在任意位置插入一个字符

替换任意字符

删除任意字符

写一个程序,实现返回最小操作次数,使得对源串进行上述这些操作后等于目标串。这就是字符串编辑距离问题。

这个问题看起来不难,很容易理解。

但是解析看起来非常复杂,暂时跳过。

3.格子取数问题

有n*n个格子,每个格子里有正数或者0,从最左上角往最右下角走,每次只能向下或者向右走,一个走两次,

把所有经过的格子里的数字加起来,求总和的最大值。

如果两次经过同一个格子,则最后求得的总和中该格子中的数只加一次。

这个问题解析大致看懂了,具体代码以后再补充。

4.交替字符串

输入三个字符串s1 s2 s3,判断第三个字符串是否由前两个字符串交错而成且不改变这两个字符串中各个字符原有的相对顺序。

我自己想了堆栈的方法。将s1 s2倒序输入到堆栈中,将s3中的元素分别与栈顶元素进行对比。如果相同则将该元素出栈;如果与两个栈顶元素均不相同,则返回false。

也可以使用动态规划的方法。看起来比较复杂,但是可以帮助对于动态规划的理解。

class Stack(object):
    def __init__(self):
        self.items = []

    def is_empty(self):
        return self.items == []

    def peek(self):
        return self.items[len(self.items)-1]

    def size(self):
        return len(self.items)

    def push(self, item):
        self.items.append(item)

    def pop(self):
        self.items.pop()


def is_interleave(str1, str2, str3):
    if len(str1) + len(str2) != len(str3):
        return False
    stack1 = Stack()
    stack2 = Stack()
    for i in str1[::-1]:
        stack1.push(i)
    for i in str2[::-1]:
        stack2.push(i)
    for i in str3:
        if i == stack1.peek():
            stack1.pop()
        elif i == stack2.peek():
            stack2.pop()
        else:
            return False
    return True

这段代码并不能实现想要的功能。因为代码中首先会尽力与str1中的字符进行匹配,然后再匹配str2中的字符。

当字符同时与两个栈顶元素相等时,无法判断某个字符应该与哪个字符串进行匹配。

即使符合交替字符串的规则,str1中的字符全部匹配之后就会因为超出范围报错。

扑街。

动态规划方法:

def is_interleave(s1, s2, s3):
    n = len(s1)
    m = len(s2)
    s = len(s3)
    if n + m != s:
        return False
    dp = [[None for i in range(m+1)] for i in range(n+1)]
    dp[0][0] = True
    for i in range(n+1):
        for j in range(m+1):
            if dp[i][j] or (i-1 >= 0 and dp[i-1][j] == True and s1[i-1] == s3[i+j-1]) or (j-1 >= 0 and dp[i][j-1] == True and s2[j-1] == s3[i+j-1]):
                dp[i][j] = True
            else:
                dp[i][j] = False
    return dp[n][m]

 

 动态规划完美解决问题。很强大。

注意if的判断条件,精髓中的精髓。

同时掌握了创建矩阵的方法,利用列表生成器。

 

posted @ 2018-04-14 19:32  铁树小寒  阅读(176)  评论(0编辑  收藏  举报