【算法】动态规划

######################## 买卖股票的最佳时机 ########################################3

def max_profix(nums):
    n = len(nums)
    res = 0
    for i in range(n):
        for j in range(i, n):
            res = max(res, nums[j] - nums[i])

    return res


def max_profix1(nums):
    res = 0
    buy = nums[0]
    for i in nums:
        if i < buy:
            buy = i
        res = max(i - buy, res)
    return res


print(max_profix1([7, 6, 4, 3, 1]))


########################## 判断子序列 ############################################

def isSubsequence(s: str, t: str) -> bool:
    location = -1
    for i in s:
        location = t.find(i, location + 1)
        if location == -1:
            return False
    return True


def isSubsequence1(s: str, t: str) -> bool:
    t = iter(t)
    return all([i in t for i in s])


# print(isSubsequence1('abc', 'ahgdcb'))


############################## 打家劫舍 #######################################33
def rob(nums):
    n = len(nums)
    dp = [0] * n
    dp[0] = nums[0]
    dp[1] = max(dp[0], nums[1])
    for i in range(2, n):
        dp[i] = max(dp[i - 1], dp[i - 2] + nums[i])
    return dp[-1]


def rob1(nums):
    pre, cur = 0, 0
    for i in nums:
        pre, cur = cur, max(cur, pre + i)

    return cur


########################## 最大回文字串 ###########################################
def longestPalindrome(s: str) -> str:
    n = len(s)
    if n < 2:
        return s

    max_len = 1
    begin = 0
    # dp[i][j] 表示 s[i..j] 是否是回文串
    dp = [[False] * n for _ in range(n)]
    for i in range(n):
        dp[i][i] = True

    # 递推开始
    # 先枚举子串长度
    for L in range(2, n + 1):
        # 枚举左边界,左边界的上限设置可以宽松一些
        for i in range(n):
            # 由 L 和 i 可以确定右边界,即 j - i + 1 = L 得
            j = L + i - 1
            # 如果右边界越界,就可以退出当前循环
            if j >= n:
                break

            if s[i] != s[j]:
                dp[i][j] = False
            else:
                if j - i < 3:
                    dp[i][j] = True
                else:
                    dp[i][j] = dp[i + 1][j - 1]

            # 只要 dp[i][L] == true 成立,就表示子串 s[i..L] 是回文,此时记录回文长度和起始位置
            if dp[i][j] and j - i + 1 > max_len:
                max_len = j - i + 1
                begin = i
    return s[begin:begin + max_len]


print(longestPalindrome('cbaabdhhc'))


########################## 最大子数组和 ###############################
def max_sub_array(nums):
    '''
    暴力解法
    第二层在第一层的基础上循环
    :param nums:
    :return:
    '''
    n = len(nums)
    result = nums[0]
    for i in range(n):
        _sum = 0
        for j in range(i, n):
            _sum += nums[j]
            result = max(result, _sum)

    return result


def max_sub_array1(nums):
    '''
    动态规划
    :param nums:
    :return:
    '''
    n = len(nums)
    pre = 0
    res = nums[0]
    for i in range(n):
        pre = max(nums[i], pre + nums[i])
        res = max(pre, res)
    return res


def max_sub_array2(nums):
    '''
    贪婪算法,顺便找出子数组位置
    :param nums:
    :return:
    '''
    start = 0
    end = 0
    res = nums[0]
    pre = 0
    for i, value in enumerate(nums):
        pre += value
        if pre >= res:
            res = pre
            end = i
        if pre < 0:
            pre = 0
            start = i + 1

    return nums[start:end + 1], sum(nums[start:end + 1])


##################### 最长系列 #########################################
def longestPalindrome(s) -> int:
    '''
    给定一个包含大写字母和小写字母的字符串s,返回通过这些字母构造成的最长的回文串
    在构造过程中,请注意区分大小写 。比如"Aa"不能当做一个回文字符串。
    示例 1:
    输入:s = "abccccdd"
    输出:7
    解释:
    我们可以构造的最长的回文串是"dccaccd", 它的长度是 7。

    输入:s = "a"
    输入:1
    '''
    from collections import Counter
    c = Counter(s)
    res = 0
    single = False
    for i in c.values():
        if i % 2 == 0:
            res += i
        else:
            if not single:
                res += 1
                single = True
            res += (i - 1)
    return res


# print(longestPalindrome("abccccdd"))

def longestCommonPrefix(strs: list) -> str:
    """
    编写一个函数来查找字符串数组中的最长公共前缀。
    如果不存在公共前缀,返回空字符串""。

    示例 1:
    输入:strs = ["flower","flow","flight"]
    输出:"fl"

    示例 2:
    输入:strs = ["dog","racecar","car"]
    输出:""
    解释:输入不存在公共前缀。
    """
    base = strs[0]
    others = strs[1:]
    end = None
    n = len(base)
    for i in range(n):
        if all([base[:i + 1] == j[:i + 1] for j in others]):
            end = i + 1
        else:
            break
    if end is not None:
        return base[:end]
    else:
        return ''


def longestCommonPrefix1(strs: list) -> str:
    if not strs:
        return ""
    print(sorted(strs))
    str0 = min(strs)
    str1 = max(strs)
    for i in range(len(str0)):
        if str0[i] != str1[i]:
            return str0[:i]
    return str0


# print(longestCommonPrefix1(["flower","flow","flight"]))

def findLength(A: list, B: list) -> int:
    def maxLength(addA: int, addB: int, length: int) -> int:
        ret = k = 0
        for i in range(length):
            if A[addA + i] == B[addB + i]:
                k += 1
                ret = max(ret, k)
            else:
                k = 0
        return ret

    n, m = len(A), len(B)
    ret = 0
    for i in range(n):
        length = min(m, n - i)
        ret = max(ret, maxLength(i, 0, length))
    for i in range(m):
        length = min(n, m - i)
        ret = max(ret, maxLength(0, i, length))
    return ret


def find_length(nums1, nums2):
    m, n = len(nums1), len(nums2)
    dp = [[0] * (m + 1) for i in range(n + 1)]
    res = 0
    for i in range(n - 1, -1, -1):
        for j in range(m - 1, -1, -1):
            dp[i][j] = dp[i + 1][j + 1] if nums1[i] == nums2[j] else 0
            res = max(res, dp[i][j])


print(findLength([1, 2, 3, 2, 1], [3, 2, 1, 4, 7]))


########################### 爬楼梯 #####################################

def climb_stairs(n):
    dp = [0] * (n + 1)
    dp[0] = 1
    dp[1] = 2
    for i in range(2, n):
        dp[i] = dp[i - 2] + dp[i - 1]
    return dp[n - 1]


def climb_stairs1(n):
    if n <= 2:
        return n
    return climb_stairs1(n - 1) + climb_stairs1(n - 2)


def climb_stairs1_1(n):
    mem = [0] * (n + 1)

    # 记忆化递归
    def dfs(n):
        if n <= 2:
            return n
        if mem[n] == 0:
            mem[n] = climb_stairs1_1(n - 1) + climb_stairs1_1(n - 2)
        return mem[n]

    return dfs(n)


def climb_stair2(n):
    pre, cur = 1, 1
    for i in range(2, n + 1):
        pre, cur = cur, pre + cur
    return cur


print(climb_stair2(4))


# ######################## 使用最小花费爬楼梯 #############################

def min_cost_climb_stairs1(cost: list):
    n = len(cost)
    dp = [0] * n
    dp[1] = min(cost[0], cost[1])

    for i in range(2, n):
        dp[i] = min(dp[i - 2] + cost[i - 1], dp[i - 1] + cost[i])

    return dp[-1]

posted @ 2022-07-12 11:10  倒骑驴子  阅读(22)  评论(0编辑  收藏  举报