编程记录

2020-03-12  本文已影响0人  wwlsm

code programming

计算数组子数组之和的最大值

def max_sub_sum_problem(arr):
    """
    问题:给定一个整数数组,计算连续子数组的最大和
    思路:以s[n]代表到n时候最大和,如果s[n-1]<0,那么a[n]应该从头开始;否则s[n]=s[n-1]+a[n]
    如果当前计算的子数组和>=0,就将当前遍历的数组成员加到里面;如果当前计算的子数组和<0,就从当前遍历的数组成员开始计算
    :return:
    """
    res, _max = 0, 0
    for i in arr:
        if res < 0:
            res = i
        else:
            res += i
        if res > _max:
            _max = res
    return _max

计算数组最长递增子序列

def max_len_sub_arr(arr):
    """
    问题:求解给定数组中最长的递增子序列
    思路:动态规划,时间复杂度O(n^2)
    :return:
    """
    dp = [1] * len(arr)
    for i in range(len(arr)):
        for j in range(i):
            if arr[j] < arr[i]:
                dp[i] = max(dp[i], dp[j] + 1)
    return max(dp)

部分反转字符串

def str_reverse(txt, start, n):
    """
    问题:字符串s旋转,给定位置start,将s[0,start]部分保持顺序情况下移动到尾部,例如start=2, s='abcdef'->'defabc'
    思路:三部反转法(X^TY^T)^T=YX, 以字符串s='abcdef', start=3为例
    1. 对于前缀字符串'abc', 旋转后变成'cba'
    2. 对于后缀字符串'def', 旋转后变成'fed'
    3. 对于旋转后字符串'cbafed', 旋转后变成'defabc'
    :param txt: 输入字符串
    :param start: 旋转后新字符串头字符
    :param n: 字符串长度
    :return: 结果
    """
    def sub_reverse(text, s, e):
        while s < e:
            text[s], text[e] = text[e], text[s]
            s += 1
            e -= 1
        return text
    _text = list(txt)
    txt = sub_reverse(_text, 0, start - 1)
    txt = sub_reverse(txt, start, n-1)
    txt = sub_reverse(txt, 0, n-1)
    return ''.join(txt)

数组子序列求和问题

def slide_widows_sum(target):
    """
    问题:给定target,求从1到target的连续整数数组中,和为target的连续整数序列
    思路:滑动窗口左右索引i,j,那么窗口内的值的和,代表了连续整数序列的和w[i, j]
    1. 如果w[i, j] < target, j++
    2. 如果w[i, j] > target, i++
    3. 如果w[i, j] == target, 记录,并将i++
    滑动窗口求连续序列和等于n的问题
    :param target: 目标值
    :return: 结果序列
    """
    i, j, _sum, res = 1, 1, 0, []
    while i <= target // 2:
        if _sum < target:
            _sum += j
            j += 1
        elif _sum > target:
            _sum -= i
            i += 1
        else:
            res.append(list(range(i, j)))
            _sum -= i
            i += 1
    return res

求解两个字符串编辑距离

def levenshtein_by_dynamic_programming(s1, s2):
    """
    问题:求解两个字符串s1, s2的编辑距离
    思路:s[i], s[j] 分别代表s1, s2的第i, j个字符, dis[i, j]代表分别从s1, s2头开始到i, j的编辑距离
    1. 如果s[i] == s[j], 那么dis[i, j] == dis[i-1, j-1]
    2. 如果s[i] ≠ s[j], 那么存在增、删、改三种操作
        1) s2增加一个s1末尾相同字符情况下:s[i] == s[j+1], dis[i, j+1] == dis[i-1, j] + 1
        2) s1增加一个s2末尾相同字符情况下:s[i+1] == s[j], dis[i+1, j] == dis[i, j-1] + 1
        3) 修改任意一个字符末尾变成相同:s[i] == s[j], dis[i, j] == dis[i-1, j-1] + 1
    动态规划——字符串的编辑距离
    s1 = "abc", s2 = "def"
    计算公式:
             | 0                                           i = 0, j = 0
             | j                                           i = 0, j > 0
    d[i,j] = | i                                           i > 0, j = 0
             | min(d[i,j-1]+1, d[i-1,j]+1, d[i-1,j-1])    s1(i) = s2(j)
             | min(d[i,j-1]+1, d[i-1,j]+1, d[i-1,j-1]+1)  s1(i) ≠ s2(j)
    定义二维数组[4][4]:
         d e f            d e f
      |x|x|x|x|        |0|1|2|3|
    a |x|x|x|x|  =>  a |1|1|2|3|  => 编辑距离d = [4][4] = 3
    b |x|x|x|x|      b |2|2|2|3|
    c |x|x|x|x|      c |3|3|3|3|
    :param s1: 第一个字符串
    :param s2: 第二个字符串
    :return: 返回的编辑距离
    """
    len_s1, len_s2 = len(s1), len(s2)
    if len_s1 == 0 and len_s2 > 0:
        return len_s2
    if len_s1 > 0 and len_s2 == 0:
        return len_s1
    mat = [[0 for __ in range(len_s1 + 1)] for _ in range(len_s2 + 1)]
    for i in range(len_s1 + 1):
        mat[0][i] = i
    for j in range(len_s2 + 1):
        mat[j][0] = j
    for i in range(1, len_s1 + 1):
        s1i = s1[i - 1]
        for j in range(1, len_s2 + 1):
            s2j = s2[j - 1]
            flag = 0 if s1i == s2j else 1
            mat[i][j] = min(mat[i - 1][j] + flag, mat[i][j - 1] + flag, mat[i - 1][j - 1] + flag)
    return mat[len_s1][len_s2]

无穷数据流采样问题

def reservoir_sampling(nums):
    """
    问题:从一个极大的数据流中,以相同概率采样nums个数据
    思路:蓄水池算法
    1. 首先蓄水满池子m
    2. 对于后续到达的第n个数据,总是以1/n的概率保留第n个数
    3. 以(n-1)/n的概率保留之前的数据,最终采样的每个数据都是1/n的概率
    :param nums:
    :return:
    """
    import random
    sample_titles = []
    for index, num in enumerate(list(range(10000000))):
        if index < nums:  # 先给池子蓄满水
            sample_titles.append(num)
        else:
            r = random.randint(0, index)
            if r < nums:
                sample_titles[r] = num
    return sample_titles

子集和问题

def subset_sum_problem(arr, target):
    """
    问题:给定一个集合,判断该集合是否存在子集A,使得A的和为target
    思路:动态规划
    1. 定义s[i, j]=True/False:表示arr中前i(含)个元素组成的集合和为j的值
    2. 基于集合性质可知:如果集合s[i, j]=True, 那么s[i+1, j]=True
        i+1元素形成的集合的子集,肯定包含i个元素形成的集合的所有子集
    3. 如果s[i, j] = False, 那么s[i+1, j] = s[i, j-arr[i+1]]
    :param arr: 数据集合
    :param target: 目标和
    :return: 结果
    """
    res = [[False for __ in range(target + 1)] for _ in range(len(arr) + 1)]
    for i in range(target + 1):
        res[0][i] = False
    for j in range(len(arr) + 1):
        res[j][0] = True
    for i in range(1, len(arr) + 1):
        for j in range(1, target + 1):
            res[i][j] = (res[i - 1][j] or res[i - 1][j - arr[i]])
    return res[len(arr) - 1][target - 1]

0-1背包问题

def zero_one_bag_problem(weight, price, target):
    """
    问题:0-1背包问题
    思路:动态规划
    1. s[i, j] 表示前i个物品下最大价值j
              | s[i - 1, j]                      (j - wi < 0)
    s[i, j] = |     | s[i - 1, j]
              | Max |                            (j - wi >= 0)
              |     | s[i - 1, j -wi] + pi
    :param weight:
    :param price:
    :param target: 
    :return:
    """
    row, col = len(weight) + 1, target + 1
    res, values = [[0 for __ in range(col)] for _ in range(row)], [0] * row
    for m in range(1, row):
        for n in range(1, col):
            if weight[m-1] < n:
                res[m][n] = max(res[m-1][n], res[m-1][n-weight[m-1]] + price[m-1])
            else:
                res[m][n] = res[m - 1][n]
    return res[-1][-1]
上一篇下一篇

猜你喜欢

热点阅读