在演算法解題領域中,機率路徑最佳化是一個經典與具有挑戰性的問題。今天玄貓要和大家分享如何運用動態規劃(Dynamic Programming)來解決一個特殊的機率路徑問題。

問題描述

我們面對的是一個 N × M 的網格,其中:

  • 網格中有障礙物(稱為「遺失的圓盤」)
  • 從頂部任一位置投放一個硬幣
  • 硬幣會沿著網格向下移動
  • 目標是找出最佳的投放位置,使硬幣以最大機率到達指定的出口

核心解題思路

讓我們採用自底向上(Bottom-up)的動態規劃方法:

def calculate_probabilities(grid_height, grid_width, target_exit, missing_discs):
    # 初始化機率矩陣
    dp = [[0.0] * grid_width for _ in range(grid_height)]
    
    # 設定目標出口的初始機率為 1.0
    dp[grid_height-1][target_exit] = 1.0
    
    # 建立遺失圓盤的集合,方便查詢
    missing_set = set((y, x) for y, x in missing_discs)
    
    # 由下而上計算每個位置的機率
    for y in range(grid_height-2, -1, -1):
        for x in range(grid_width):
            if (y, x) not in missing_set:
                # 計算左右分支的機率
                left_prob = dp[y+1][x-1] if x > 0 else 0.0
                right_prob = dp[y+1][x+1] if x < grid_width-1 else 0.0
                
                # 根據位置計算總機率
                if (x + y) % 2 == 0:  # 有圓盤的位置
                    dp[y][x] = (left_prob + right_prob) / 2.0
                else:  # 無圓盤的位置
                    dp[y][x] = max(left_prob, right_prob)
    
    return dp[0]  # 回傳頂層所有位置的機率

程式碼解密

  1. 初始化階段
  • 建立一個二維陣列 dp,用於儲存每個位置的機率值
  • 將目標出口的機率設為 1.0,作為動態規劃的起始點
  1. 遺失圓盤處理
  • 使用集合(Set)資料結構儲存遺失圓盤的位置
  • 提供 O(1) 的時間複雜度來檢查特定位置是否有圓盤
  1. 動態規劃計算
  • 從底層向上計算每個位置的機率
  • 對於有圓盤的位置,機率為左右兩個方向的平均值
  • 對於無圓盤的位置,選擇左右兩個方向中的最大機率

效能最佳化策略

為了在限定時間內完成大量測試案例的計算,我們採用了以下最佳化策略:

class ProbabilityCalculator:
    def __init__(self):
        self.cache = {}  # 快取已計算過的結果
        
    def get_optimal_path(self, grid_height, grid_width, target_exit, missing_discs):
        # 建立快取鍵值
        cache_key = (grid_height, grid_width, target_exit, tuple(sorted(missing_discs)))
        
        # 檢查快取是否存在結果
        if cache_key in self.cache:
            return self.cache[cache_key]
            
        # 計算新的結果
        probabilities = calculate_probabilities(
            grid_height, grid_width, target_exit, missing_discs
        )
        
        # 找出最佳起始位置
        max_prob = max(probabilities)
        best_position = probabilities.index(max_prob)
        
        # 儲存結果到快取
        result = (best_position, max_prob)
        self.cache[cache_key] = result
        
        return result

最佳化重點說明

  1. 記憶體快取
  • 使用字典儲存已計算過的結果
  • 避免重複計算相同的輸入引數
  1. 資料結構最佳化
  • 使用元組(Tuple)作為快取的鍵值,提供不可變性
  • 對遺失圓盤位置進行排序,確保相同設定能夠命中快取
  1. 時間複雜度分析
  • 單次計算時間複雜度:O(grid_height × grid_width)
  • 使用快取後,重複計算的時間複雜度降為 O(1)

這個解決方案能夠有效處理最大 99×100 的網格,並在 6 分鐘內完成 100 個不同測試案例的計算。透過動態規劃與快取機制的結合,我們成功將原本指數級的複雜度降低到可接受的範圍。

在實際應用中,這種演算法不只適用於本題,還可以應用在許多類別似的機率路徑規劃問題上。例如機器人路徑規劃、網路由選擇等領域。玄貓在實作過程中發現,關鍵在於正確建立動態規劃的遞迴關係,並善用記憶體空間來換取時間效能。

在處理字串排序問題時,選擇適當的演算法對效能有重大影響。本文將探討兩種不同的Python實作方法,分別適用於不同的使用場景。

暴力窮舉法實作

第一種方法是使用Python的排列組合函式庫

from itertools import permutations

def sort_by_permutation(text):
    words = text.split()
    answer = min("".join(combination) for combination in permutations(words))
    return answer
  • 使用 itertools.permutations 產生所有可能的排列組合
  • split() 將輸入字串分割成單字列表
  • min() 找出所有組閤中字典序最小的結果
  • 時間複雜度為 O(N!),N 為單字數量
  • 適用於小規模資料集(N ≤ 9

在 Python 程式開發中,字串處理是一項常見與重要的任務。今天玄貓要和大家分享一些關於字串接與排序的進階技巧,特別是在處理大量字串資料時的最佳實踐。

字串接的基礎概念

在 Python 中,字串接有多種方式,最基本的方法包括:

# 使用加號運算元
str1 = "Hello"
str2 = "World"
result = str1 + " " + str2  # Hello World

# 使用 join() 方法
words = ["Hello", "World"]
result = " ".join(words)  # Hello World

進階字串排序技巧

當需要對字串進行特殊排序時,我們可以使用自訂的比較函式:

def custom_sort(strings):
    return "".join(sorted(strings, key=lambda x,y: 1 if x+y > y+x else -1))

# 使用範例
strings = ["50", "2", "1", "9"]
result = custom_sort(strings)

內容解密

  1. sorted() 函式:Python 內建的排序函式,會回傳一個新的已排序列表
  2. lambda x,y: 1 if x+y > y+x else -1
    • 自訂比較函式,比較兩個字串接後的大小
    • x+y 代表將兩個字串直接相連
    • 如果 x+y 大於 y+x,回傳 1;否則回傳 -1
  3. join() 方法:將排序後的字串列表合併為單一字串

效能最佳化考量

在處理大量字串資料時,玄貓建議注意以下幾點:

  1. 使用 join() 而非 + 運算元:
# 較佳做法
result = "".join(["Hello", "World"])

# 避免使用
result = "Hello" + "World"  # 當處理大量字串時效能較差
  1. 善用列表生成式:
# 高效率的字串處理
strings = ["a", "b", "c"]
processed = "".join(s.upper() for s in strings)

實用的字串處理技巧

除了基本的串接和排序,玄貓還要分享一些實用的字串處理技巧:

# 使用 split() 進行字串分割
text = "Hello World Python"
words = text.split()  # ['Hello', 'World', 'Python']

# 字串格式化
name = "Python"
version = 3.9
info = f"Programming with {name} {version}"

在實際開發中,合理運用這些字串處理技巧不僅能提升程式碼的可讀性,還能大幅提升執行效能。字串處理看似簡單,但要寫出高效與優雅的程式碼,需要對 Python 的字串處理機制有深入的理解。

Python 的字串處理功能強大與靈活,透過這些最佳化技巧,我們可以寫出更有效率的程式碼。玄貓建議在實際開發中,應該根據具體場景選擇最適合的字串處理方式,同時注意程式碼的可讀性和維護性。掌握這些技巧,將幫助你在處理文字資料時事半功倍。