algorithm

2021-04-26  本文已影响0人  Cindy小隐

################斐波那契数列#######################

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


def fibonacci_memo(n):
    memo = [0] * (n + 1)

    def fibonacci(n):
        if n == 1 or n == 2:
            return 1
        if n < 1:
            return -1
        if memo[n] != 0:
            return memo[n]
        memo[n] = fibonacci_memo(n-1) + fibonacci_memo(n-2)
        return memo[n]
    return fibonacci(n)


def fibonacci_dp_table(n):
    if n < 1:
        return -1
    dp_table = [0] * (n+1)
    dp_table[1], dp_table[2] = 1, 1
    for i in range(3, n+1):
        dp_table[i] = dp_table[i-1] + dp_table[i-2]
    return dp_table[n]


print(fibonacci(20))
print(fibonacci_memo(20))
print(fibonacci_dp_table(20))

######################最长递增子序列##############

# 时间复杂度N**2
test = [4, 6, 7, 9, 1, 2, 3, 2]

# base case
dp = [1] * len(test)

# 状态转移
total = 0
for i in range(len(test)):
    for j in range(i):
        total += 1
        print(i, j)
        if test[j] < test[i]:
            dp[i] = max(dp[i], dp[j]+1)

result = max(dp)
print(total)
print(result)

######################求两个字符串的最长公共子串##############

def lcs(str1, str2):
    m, n = len(str1), len(str2)
    dp = (m*[0])*n
    for i in range(1, m+1):
        for j in range(1, n+1):
            if str1[i-1] == str2[j-1]:
                dp[i][j] = dp[i-1][j-1] + 1
            else:
                dp[i][j] = max(dp[i][j-1], dp[i-1][j])
    return dp[m][n]

###############最小编辑距离###################

def min_distance(s1, s2):
    # 暴力解法
    def dp(i, j):
        # 返回值就是s1[0..i] 和 s2[0..j]的最小编辑距离
        if i == -1:
            return j+1
        if j == -1:
            return i+1
        if s1[i] == s2[j]:
            return dp(i-1, j-1)  # 什么都不做
        else:
            return min(
                # 递归
                dp(i, j-1) + 1,  # 插入
                dp(i-1, j) + 1,  # 删除
                dp(i-1, j-1) + 1  # 替换
                )
    return dp(len(s1)-1, len(s2)-1)

def min_distance2(s1, s2):
    # 动态规划解法
    memo = dict()  # 备忘录
    def dp(i, j):
        # 先查备忘录,避免重复计算
        if (i, j) in memo:
            return memo[(i, j)]
        # base case
        if i == -1:
            return j+1
        if j == -1:
            return i + 1
        if s1[i] == s2[j]:
            memo[(i, j)] = dp(i-1, j-1)
        else:
            memo[(i, j)] = min(
                # 递归
                dp(i, j - 1) + 1,  # 插入
                dp(i - 1, j) + 1,  # 删除
                dp(i - 1, j - 1) + 1  # 替换
            )
        return memo[(i, j)]
    return dp(len(s1) - 1, len(s2) - 1)


def min_distance3(s1, s2):
    # dp table 解法
    import numpy as np
    m, n = len(s1), len(s2)
    dp = np.zeros((m+1, n+1))
    # base case
    for i in range(1, m+1):
        dp[i][0] = i
    for j in range(1, n+1):
        dp[0][j] = j
    # 自底向上求解
    for i in range(1, m+1):
        for j in range(1, n+1):
            if s1[i-1] == s2[j-1]:
                dp[i][j] = dp[i-1][j-1]
            else:
                dp[i][j] = min(
                    # 递归
                    dp[i][j - 1] + 1,  # 插入
                    dp[i-1][j] + 1,  # 删除
                    dp[i-1][j-1] + 1  # 替换
                )
    return int(dp[m][n])


x = min_distance("abcd", "abcde")
y = min_distance3("abcd", "abcde")
print(y)

##########最长回文子序列##########################

# 子序列 vs 子串,前者是不连续序列,后者是连续的;求解时一般子序列更困难
# 求最长回文子序列
import numpy as np
def long_palindrome_subseq(s):
    n = len(s)
    dp = np.zeros((n, n))
    # base case
    for i in range(n):
        dp[i][i] = 1
    # 反向遍历保证正确的状态转移
    for i in range(n-2, -1, -1):
        for j in range(i+1, n):
            # 状态转移方程
            if s[i] == s[j]:
                dp[i][j] = dp[i+1][j-1] + 2
            else:
                dp[i][j] = max(dp[i+1][j], dp[i][j-1])
    return dp[0][n-1]


s = "kfdhjaklnfl"
res = long_palindrome_subseq(s)
print(res)

##############背包问题###########################

# 0-1背包问题

import numpy as np
def knapsack(N, W, wt, val):
    # N代表物品数量, W代表背包能装的重量, wt代表每个物品的重量,
#  val代表每个物品的价值
    dp = np.zeros((N+1, W+1))
    for i in range(N):
        dp[i][0] = 0
    for j in range(W):
        dp[0][j] = 0
    for i in range(1, N+1):
        for j in range(1, W+1):
            # print(i, j, wt[i-1])
            if j - wt[i-1] < 0:
                # 背包总体容量<当前物品重量,只能选择不装入背包
                dp[i][j] = dp[i-1][j]
            else:
                # 装入或不装入背包
                dp[i][j] = max(
                    dp[i-1][j-wt[i-1]]+val[i-1],   # 把物品装进背包, =在不装i物品的情况下最大价值+i物品价值
                    dp[i-1][j]  # 不把i物品装进背包
                )
    return dp


dp = knapsack(3, 4, [2,1,3], [4, 2, 3])
print(dp[3][4])

# 子集背包问题,输入一个只包含正整数的非空数组nums,
# 判断这个数组是否可以被分割成两个子集,使得两个子集的元素和相等
def can_partition(nums):
    total = sum(nums)
    n = len(nums)
    if total % 2 != 0:
        return False
    bi_total = int(total / 2)
    dp = np.zeros((n+1, bi_total+1))
    dp = np.array(dp, dtype=bool)
    for i in range(1, n+1):
        dp[i][0] = True  # 背包没有空间的时候就是装满了
    for i in range(1, n+1):
        for j in range(1, bi_total+1):
            if j - nums[i-1] < 0:
                dp[i][j] = dp[i-1][j]
            else:
                dp[i][j] = dp[i-1][j] or dp[i-1][j-nums[i-1]]
    return dp[n][bi_total]
def can_partition2(nums):
    total = sum(nums)
    n = len(nums)
    if total % 2 != 0:
        return False
    bi_total = int(total / 2)
    dp = np.zeros(bi_total+1)
    dp = np.array(dp, dtype=bool)
    dp[0] = True  # 背包没有空间的时候就是装满了
    for i in range(n):
        for j in range(bi_total, 0, -1):
            if (j - nums[i]) >= 0:
                dp[j] = dp[j] or dp[j-nums[i]]
    return dp[bi_total]
res1 = can_partition([1,5,11,5])
res2 = can_partition2([1,5,11,5])
print(res1, res2)
# 给定K种面值的硬币,面值分别为c1, c2, ..., ck, 每种硬币的数量无限,
# 再给一个总金额amount, 最少需要几枚硬币凑出这个金额,
# 如果不可能凑出,算法返回-1。

def coin_change(coins, amount):
    dp = [amount+1] * (amount+1)
    dp[0] = 0
    for i in range(amount+1):
        for coin in coins:
            if (i - coin) < 0:
                continue
            dp[i] = min(dp[i], 1+dp[i-coin])
    if dp[amount] == (amount+1):
        return -1
    else:
        return dp[amount]
res = coin_change([1], 13)
print(res)
# 完全背包问题,零钱兑换ii,给定不同面额的coins和一个总金额amount,
# 写一个函数来计算可以凑成总金额的硬币组合数,
# 假设每一种面额的金币有无限个。
def change(amount, coins):
    if len(coins) == 1 and coins[0] != amount:
        return 0
    length = len(coins)
    dp = np.zeros((length+1, amount+1))
    for i in range(length+1):
        dp[i][0] = 1
    for i in range(1, length+1):
        for j in range(1, amount+1):
            if (j - coins[i-1]) >= 0:
                dp[i][j] = dp[i-1][j] + dp[i][j - coins[i-1]]
            else:
                dp[i][j] = dp[i-1][j]
    return dp[length][amount]
res = change(10, [1, 2, 5])
print(res)

##################vivo1###################

# 一个完整的软件项目往往会包含很多由代码和文档组成的源文件。
# 编译器在编译整个项目的时候,可能需要按照依赖关系来依次编译每个源文件。
# 比如,A.cpp 依赖 B.cpp,那么在编译的时候,编译器需要先编译 B.cpp,才能再编译 A.cpp。
# 假设现有 0,1,2,3 四个文件,0号文件依赖1号文件,1号文件依赖2号文件,3号文件依赖1号文件,则源文件的编译顺序为 2,1,0,3 或 2,1,3,0。
# 现给出文件依赖关系,如 1,2,-1,1,表示0号文件依赖1号文件,1号文件依赖2号文件,2号文件没有依赖,3号文件依赖1号文件。
# 请补充完整程序,返回正确的编译顺序。注意如有同时可以编译多个文件的情况,按数字升序返回一种情况即可,比如前述案例输出为:2,1,0,3

import heapq
def compileSeq(input_):
    # write code here
    nums = [int(x) for x in input_.split(",")]
    n = len(nums)
    in_degree = [0] * n
    relation = [set() for _ in range(n)]
    res = []
    que = []
    # 获取
    for i in range(n):
        if nums[i] != -1:
            in_degree[i] += 1
            relation[nums[i]].add(i)
    print(in_degree)
    print(relation)
    for i in range(n):
        if in_degree[i] == 0:
            que.append(i)

    while que:
        cur = que[0]
        que = que[1:]
        res.append(cur)
        for idx in relation[cur]:
            in_degree[idx] -= 1
            if in_degree[idx] == 0:
                heapq.heappush(que, idx)
    string = ",".join([str(x) for x in res])
    return string


def compileSeq2(input_):
    a = list(map(int, input_.split(',')))
    n = len(a)
    dic = {}
    sq = []
    sq1 = []
    for i in range(n):
        dic[i] = a[i]
    for i in range(n):
        if dic[i] == -1:
            sq.append(i)
    while len(sq) < n:
        for i in range(n):
            if dic[i] in sq and i not in sq:
                sq.append(i)
                break
    for i in range(n):
        sq1.append(str(sq[i]))
    a = ','.join(sq1)
    return a
print(compileSeq2("1,2,-1,1"))

#####################动态规划-以最小插入次数构造回文串###########

# 回文字符串就是正读和反读都一样的字符串,
# 如“viv”、“nexen”、“12321”、“qqq”、“翻身把身翻” 等。
# 给定一个非空字符串 str,在最多可以删除一个字符的情况下请
# 编程判定其能否成为回文字符串;如果可以则输出首次删除一个
# 字符所能得到的回文字符串,如果不行则输出字符串 "false" 。

import copy
def is_palinoric(string):
    flag = True
    length = len(string)
    for i in range(length//2):
        if string[i] != string[-i-1]:
            flag = False
            break
    return flag

def after_del_is_palinoric(string):
    str_list = list(string)
    if is_palinoric(string):
        print(string)
    else:
        for idx, _ in enumerate(string):
            tmp_list = copy.deepcopy(str_list)
            tmp_list.pop(idx)
            candidate = "".join(tmp_list)
            if is_palinoric(candidate):
                return candidate
        else:
            return False
string = "abab"
res = after_del_is_palinoric(string)
print(res)

################vivo3#####################

# vivo游戏中心的运营小伙伴最近接到一款新游戏的上架申请,
# 为了保障用户体验,
# 运营同学将按运营流程和规范对其做出分析评估。
#经过初步了解后分析得知,
# 该游戏的地图可以用一个大小为 n*n 的矩阵表示,
#每个元素可以视为一个格子,
# 根据游戏剧情设定其中某些格子是不可达的
#(比如建筑、高山、河流或者其它障碍物等),
# 现在请你设计一种算法寻找从起点出发到达终点的最优抵达路径,
#以协助运营小伙伴评估该游戏的可玩性和上手难度。

def dfs(x, y, grid, endx, endy, visited, count):
    if x < 0 or y < 0 or x >= len(grid) or y >= len(grid) or grid[x][y] in "#@" \
            or (visited[x][y] != 0 and visited[x][y] <= count):
        return
    visited[x][y] = count
    if x == endx and y == endy:
        return
    dfs(x, y + 1, grid, endx, endy, visited, count + 1)
    dfs(x, y - 1, grid, endx, endy, visited, count + 1)
    dfs(x - 1, y, grid, endx, endy, visited, count + 1)
    dfs(x + 1, y, grid, endx, endy, visited, count + 1)


if __name__ == "__main__":
    n = int(input())
    [starty, startx, endy, endx] = list(map(int, input().split()))
    road = []
    for i in range(n):
        road.append(list(input()))
    visited = [[0] * n for _ in range(n)]
    dfs(startx, starty, road, endx, endy, visited, 1)
    print(visited[endx][endy] - 1)

####################二分查找法########################

test = [1, 2, 3, 2, 4, 6, 7, 9]
search_ele = 9
left = 0; right = len(test)
test.sort()
print(test)
while left < right:
    mid = (left+right)//2
    if search_ele < test[mid]:
        right = mid - 1
    elif search_ele > test[mid]:
        left = mid + 1
    else:
        print(mid)
        break

##################动规之正则表达式################

##################动规之高楼扔鸡蛋################

##################动规之戳气球问题################

##################数据结构之二叉搜索树################

##################数据结构之二叉搜索树################

上一篇下一篇

猜你喜欢

热点阅读