達成するためのPythonのデータ構造(7)

1つのバック

8つのクイーン問題を解決するためのアルゴリズムをバックトラックの1.1 Pythonの使用

'''
利用回溯算法求解八皇后问题
'''
class FindQueen:
    def __init__(self):
        self.total = 0      # 八皇后解的个数
        self.table = [[0 for i in range(8)] for i in range(8)]    # 8 x 8 的棋盘
        
    def findQueen(self, row):
        if row > 7:       # 八皇后问题有解了(已经排到了第9行)
            self.total += 1
            self.printQueen()
            return
        for coloumn in range(8):
            if self.check(row, coloumn):
                self.table[row][coloumn] = 1
                self.findQueen(row+1)
                self.table[row][coloumn] = 0       # 每趟递归退出后都需将这趟递归每行置1的位置清零
    
    def check(self, row, col):
        for n in range(8):       # 检查行列两个方向的有效性
            if self.table[n][col] or self.table[row][n]:
                return False
            
        # 检查左对角线    
        lf = [self.table[row+i][col+j] for i,j in zip(range(-7,8),range(7,-8,-1)) \
              if 0 <= row+i < 8 and 0 <= col+j < 8 and self.table[row+i][col+j]==1]
        if len(lf):
            return False
        
        # 检查右对角线
        rt = [self.table[row+i][col+j] for i,j in zip(range(-7,8),range(-7,8)) \
              if 0 <= row+i < 8 and 0 <= col+j < 8 and self.table[row+i][col+j]==1]
        if len(rt):
            return False
        
        return True
    
    def printQueen(self):
        for val in self.table:
            print(val)
        print('\n')

solutions = FindQueen()

solutions.findQueen(0)
print(solutions.total)

0-1ナップザック問題を解決するためのバックトラッキングアルゴリズムの1.2 Pythonの使用

def bag01(N, V, C, W):
	'''
	:param N:N件物品
	:param V:Value数组,对应每件物品的价值
	:param C:Capacity,指背包的最大容量
	:param W:Weight数组,对应每件物品的重量
	'''
    bestResult = [0] * N; curResult = [0] * N
    curCost = 0; curValue = 0; bestValue = 0
    
    def backtracking(depth):
        nonlocal curCost,curValue,bestValue
        if depth > N-1:
            if curValue > bestValue:
                bestValue = curValue
                bestResult[:] = curResult[:]
                print(bestResult)
                print(bestValue)
            
        else:
            for i in [0, 1]:       # 取或不取这件物品
                curResult[depth] = i
                
                if i == 0:     # 不取这件物品
                    backtracking(depth+1)
                else:
                    if curCost + W[depth] <= C:
                        curCost += W[depth]
                        curValue += V[depth]
                        backtracking(depth+1)
                        # 往上回溯,恢复现场
                        curCost -= W[depth]
                        curValue -= V[depth]
    backtracking(0)
    
    return bestResult, bestValue

bag01(4,[1500,3000,2000,1000],4,[1,4,3,0.5])
=================================================
([1, 0, 1, 0], 3500)

2 分治

逆数のデータセットに対して分割統治アルゴリズムを使用して2.1のPython

'''
利用归并排序的思想,在归并排序的过程中找到各个逆序对输出即可
'''
count = 0
def mergeSort(array1, low, high):
    array2 = [None] * 100
    if low == high:
        return 
    else:
        mid = (low + high) // 2
        mergeSort(array1, low, mid)
        mergeSort(array1, mid+1, high)
        merge(array1, array2, low, mid, high)
        array1[low:high+1] = array2[low:high+1]   # 恢复原数组
    
def merge(a1, a2, low, mid, high):
    i = low; j = mid+1; k = i; global count
    while i <= mid and j <= high:
        if a1[i] <= a1[j]:
            a2[k] = a1[i]        # 保护原数组
            i += 1; k += 1
        else:
            count += mid-i+1
            for _ in range(i,mid+1):
                print(a1[_],a1[j])
            a2[k] = a1[j];k+=1;j+=1
            
    while i <= mid:
        a2[k] = a1[i]
        k += 1; i += 1
    while j <= high:
        a2[k] = a1[j]
        k += 1; j += 1        
      
r =[23,13,35,6,19,50,28,38,26,17,45]
mergeSort(r, 0, 10)
print(count)

3動的計画

3.1 Python動的プログラミング0-1ナップザック問題

問題の説明:N項目があり、体重の各項目[I]、Cの値W [i]は、唯一の各項目の
DPを有する[I] [V] iは項目(1 <= iが<正面を示し最大値= N、0 <= V < = V) を得ることができるだけ充電容量Vのバックパックは
、項目の選択の2つの戦略は、iが存在する:
1:i番目に配置されていない項目は、その後アイテムへの前者の問題は、正確にI-1を得ることができるバックパックにおけるVの最大負荷容量値、すなわちDP [I-1] [V]
2:私の項目を追加し、私の前に問題に変換されます。正確アイテムの最大値-1充電容量VW [i]はバックパックを得ることができる、すなわち、DP [I-1] [VW [I] + C [i]は
状態遷移方程式を得ることができます。

DP [I] [V] =最大{DP [I-1]を[V]、DP [I-1] [VW [I] + C [I]}

我々は、[0] [v] = 0は、再帰的配列全体のDP、すなわち最適解の最大値に対応するDPアレイを開始DPの境界でき

時間の複雑さを、最適化されていませんスペースの複雑さを最適化

  • 状態遷移方程式を介して、我々は、二次元アレイはDP見ることができる、DP [i]は、行データDPを使用することである[I-1]は、行ごとに算出されます
  • 正確には、DP [I]を計算するときに、[V]、我々はデータDPを使用して、[I-1] [V]とデータDP [V]左側の[I-1] DP [I-1] [VW [I]]。
  • データDP [I + 1]のラインを計算すると、データDPは、[I-1]ラインアップする必要はありません。

私たちは[]を構築することにより、一次元配列のDPをスクロールすることができます考えることができます。

  • DPのための[V]、転送それはDPの前に示される前に、[I-1] [V]、それは[V]、それが正しいDP前左データの[I-1] DPの前に残っています[I]、[V]は、データの右(DP用は[I + 1] [V]を使用して計算される)、即ち、一次元転送する前に、DPを介して転送計算した後、時刻DPにおける配列[V] [V]とDPは結果は、[V]は、前のデータから計算され、DP [V]で連続使用してそのような物品の下で継続に供給繰り返した後

したがって、状態遷移方程式:

DP [V] =最大{DP [V]、DP [VW [I] + C [I]}
def bag01DP(N, C, W, V):
    '''
    动态规划求解01背包问题
    :param N: 物品的件数
    :param C: 物品的价值数组
    :param W: 物品的重量数组
    :param V: 背包的容量
    '''
    dp = [0] * (V+1)    # 0 到 V
    for index in range(N):
    	# 每行都是要将那个index对应的物品放入包中再进行计算
        for v in range(V, W[index]-1, -1):  
            '''
            这里v表示容量从W[index]到V的背包,每次减1,这是由物品重量的粒度决定的
            若物品重量不全是整数,则需要调整减少的粒度大小
            如物品重量有为5.5的,则每次减少的则为0.5
            '''
            dp[v] = max(dp[v], dp[v-W[index]]+ C[index])
    return max(dp)

bag01DP(5,[4,5,2,1,3],[3,5,1,2,2],8)
================
10

3.2のpython達成し、最小パスを解決

def minPathSum(grid):
    sum = 0; height = len(grid); width = len(grid[0])
    dp = [[0 for x in range(width)] for y in range(height)] # 注意不能使用 [[0] * width] * height,此为浅复制,不同坐标指向了同一块内存
    dp[0][0] = grid[0][0]
    for col in range(1,width):      # 初始化第一行
        dp[0][col] = dp[0][col-1] + grid[0][col]
    for row in range(1,height):     # 初始化第一列
        dp[row][0] = dp[row-1][0] + grid[row][0]       
    for i in range(1,height):
        for j in range(1,width):
            dp[i][j] = min(dp[i-1][j]+grid[i][j],dp[i][j-1]+grid[i][j])
    
    return dp[height-1][width-1]

3.3 Pythonは最短レーベンシュタイン編集距離を実現します

import numpy as np
def LevenshteinDistance(str1, str2):
    '''
    str1与str2的莱文斯坦最短编辑距离
    '''
    len1 = len(str1); len2 = len(str2)
    '''
    创建一个dp数组存储状态转移方程的结果
    dp[i][j]中i对应str1,j对应str2
    考虑到还有空串的情况,对应位置在i==0或j==0的位置,故数组下标为0 到 len1,len2
    '''
    dp = np.zeros((len1+1,len2+1)) 
    
    # 当str1或str2为空串时,最小编辑距离即为非空串的长度,以此初始化第一行和第一列
    for col in range(1,len2+1):   # 初始化第一行
        dp[0][col] = col
    for row in range(1,len1+1):   # 初始化第一列
        dp[row][0] = row
        
    for i in range(1,len1+1):
        for j in range(len2+1):
            k = 0 if str1[i-1] == str2[j-1] else 1      # 注意字符串中的下标比数组的下标要少1才是对应的字符位置
            dp[i][j] = min(dp[i][j-1] + 1, dp[i-1][j] + 1, dp[i-1][j-1] + k)
    
    return dp[-1][-1]

LevenshteinDistance('kitten','sitting')
======================
3.0

最長共通部分列3.4 Pythonの実装では、二つの文字列を探します

'''
最长公共子序列的状态转移方程为:(和最短编辑距离类似,只和左方,上方,左上方的元素有关)
①当str1[i] == str2[j]时:dp[i][j] = dp[i-1][j-1] + 1
②当str1[i] != str2[j]时:dp[i][j] = max(dp[i][j-1], dp[i-1][j])
'''
def LCS(str1, str2):
    # 寻找str1和str2的最长公共子序列
    len1 = len(str1); len2 = len(str2)
    dp = [[0 for x in range(len2)] for y in range(len1)]   # 开辟一个二维数组dp,初始全为0
    dp[0][0] = 1 if str1[0] == str2[0] else 0
    for col in range(1,len2):
        dp[0][col] = 1 if str1[0] == str2[col] else dp[0][col-1]   # 初始化第一行
    for row in range(1,len1):
        dp[row][0] = 1 if str1[row] == str2[0] else dp[row-1][0]   # 初始化第一列  
    for i in range(1,len1):
        for j in range(1,len2):
            dp[i][j] = max(dp[i][j-1], dp[i-1][j]) if str1[i] != str2[j] else dp[i-1][j-1] + 1
    
    return dp[-1][-1]

LCS('sitting','kittenkkg')
========================
5

3.5のpython最長増加部分列のデータ・シーケンスを実装

def LIS(lst):
    length = len(lst)
    dp = [0 for _ in range(length)]
    dp[0] = 1; maxdp = 1
    for i in range(1, length):
        for j in range(i):
            if lst[j] < lst[i] and dp[j] >= dp[i]:
                dp[i] = dp[j] + 1
                # dp数组最大值若大于1,则它一定是通过上一条语句计算出来的
                maxdp = dp[i]       
    return maxdp

LIS([1,3,5,2,4,6,7,8,0])
=====================
6

4つのLeetCode関連の演習

電話番号(17)の4.1手紙の組み合わせ(文字の組み合わせの電話番号)

ときに実行:40ミリ、電話番号ののpython3は、ユーザーの99.19パーセントの手紙組み合わせ敗北提出の
メモリ消費量:13メガバイトは、電話番号の提出ユーザーのpython3の手紙組み合わせの95.74パーセントを打ちます

class Solution:
    def letterCombinations(self, digits: str) -> List[str]:
        if digits:
            len1 = len(digits)
            num2letter = {'2':'abc','3':'def','4':'ghi','5':'jkl','6':'mno','7':'pqrs','8':'tuv','9':'wxyz'}
            set1 = num2letter[digits[0]]
            result = []
            def backtrack(level, str1, set1):
                '''if level == len1-1:
                    result.append(str1)
                    return '''
                for letter in set1:
                    str1 += letter
                    if level < len1-1:
                        backtrack(level+1, str1, num2letter[digits[level+1]])
                    if len(str1) == len1:
                        result.append(str1)
                    str1 = str1[:-1]
                return result
            return backtrack(0,'',num2letter[digits[0]])
        return []

4.2順列(46)

class Solution:
    def permute(self, nums: List[int]) -> List[List[int]]:
        result = []
        def perm(nums, end):
            if end == 0:
                result.append(nums[:])
            else:
                for i in range(end+1):
                    nums[i], nums[end] = nums[end], nums[i]
                    perm(nums, end-1)
                    nums[i], nums[end] = nums[end], nums[i]
            return result
        return perm(nums, len(nums)-1)

4.3コインチェンジ(変化交換)

性質が完全ナップザック問題であり、DP [i]は量の私のために必要なコインの最小数を表します。

class Solution:
    def coinChange(self, coins: List[int], amount: int) -> int:
        if amount < 0:return -1
        dp = [float('inf')] * (amount+1)
        dp[0] = 0
        for i in range(1,amount+1):
            for coin in coins:
                if coin <= i:
                    dp[i] = min(dp[i], dp[i-coin]+1)      # 状态转移方程
                    
        return dp[amount] if dp[amount] != float('inf') else -1

4.4

売却するのに利用できるi日の最善の利益に記録されている(購入の日に)は、i-録音minnum日の最低価格の前に、MAXNUM

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        if prices:
            len1 = len(prices)
            if len1 == 1:return 0
            minnum = prices[0]; maxnum = -float('inf')
            for i in range(1, len1):
                minnum = min(minnum, prices[i])
                maxnum = max(maxnum, prices[i]-minnum)
            return maxnum
        return 0

おすすめ

転載: blog.csdn.net/shichensuyu/article/details/90583312