首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 更多程式設計知識

Ruby 實現最長公共子序列 (LCS) 動態規劃演算法

     編輯:更多程式設計知識

最長公共子序列問題:給定兩序列,找出最長的子序列(不要求連續)同時出現在兩者中。本文提供標準動態規劃 Ruby 實作,包含長度矩陣建構、方向追蹤矩陣、遞迴回溯列印 LCS 內容。

完整程式碼


# encoding: utf-8

# 隨機生成測試序列
chars = ('a'..'e').to_a
x, y = [], []
(rand(5)+5).times { x << chars[rand(chars.size)] }
(rand(5)+5).times { y << chars[rand(chars.size)] }
printf("The random character arrays are: %s and %s\n", x.inspect, y.inspect)

m, n = x.size, y.size
c = Array.new(m+1) { Array.new(n+1, 0) }  # 長度矩陣
b = Array.new(m+1) { Array.new(n+1) }     # 方向矩陣: 0=斜上, 1=上, 2=左

# DP 填表
(1..m).each do |i|
  (1..n).each do |j|
    if x[i-1] == y[j-1]
      c[i][j] = c[i-1][j-1] + 1
      b[i][j] = 0  # 斜上 (匹配)
    else
      if c[i-1][j] >= c[i][j-1]
        c[i][j] = c[i-1][j]
        b[i][j] = 1  # 上
      else
        c[i][j] = c[i][j-1]
        b[i][j] = 2  # 左
      end
    end
  end
end

# 遞迴回溯列印 LCS
def print_lcs(x, b, i, j)
  return if i == 0 || j == 0
  if b[i][j] == 0
    print_lcs(x, b, i-1, j-1)
    print "#{x[i-1]} "
  elsif b[i][j] == 1
    print_lcs(x, b, i-1, j)
  else
    print_lcs(x, b, i, j-1)
  end
end

print "The Longest-Common-Subsequence is: "
print_lcs(x, b, m, n)
puts

執行範例


The random character arrays are: ["b", "a", "c", "a", "a", "b", "d"] and ["a", "c", "a", "c", "a", "a", "b"]
The Longest-Common-Subsequence is: a c a a b

演算法解析

狀態定義

  • c[i][j]:X[1..i] 與 Y[1..j] 的 LCS 長度
  • b[i][j]:最優解來源方向
    • 0:X[i]==Y[j],來自 c[i-1][j-1] (斜上)
    • 1:來自 c[i-1][j] (上)
    • 2:來自 c[i][j-1] (左)

轉移方程

if X[i] == Y[j]:
    c[i][j] = c[i-1][j-1] + 1
    b[i][j] = 0
else:
    c[i][j] = max(c[i-1][j], c[i][j-1])
    b[i][j] = (c[i-1][j] >= c[i][j-1]) ? 1 : 2

回溯邏輯

  • 從 c[m][n] 起始,依 b 方向遞迴
  • 方向 0:輸出字元,移至 (i-1, j-1)
  • 方向 1:移至 (i-1, j)
  • 方向 2:移至 (i, j-1)

複雜度

  • 時間:O(mn)
  • 空間:O(mn) — 可優化至 O(min(m,n)) 僅保留長度,但無法回溯列印 LCS 內容

變體與應用

變體修改點應用
最長公共子串要求連續,不匹配時歸零相似度檢測、病毒特徵碼
編輯距離允許替換操作拼字檢查、DNA 比對
最長遞增子序列 (LIS)單序列,轉化為 LCS版本號排序、橋樑建設
多序列 LCS擴充至 k 維 DP多基因組比對

Ruby 實作細節

  • Array.new(m+1) { Array.new(n+1, 0) }:正確建立二維陣列,避免淺拷貝陷阱。
  • x[i-1]:Ruby 陣列 0-based,DP 邏輯 1-based,統一轉換。
  • print_lcs 遞迴深度 ≤ min(m,n),安全範圍內。
  • 隨機測試資料生成:(rand(5)+5).times 產生 5-9 長度序列。

總結

LCS 是動態規劃經典入門題。Ruby 程式碼清晰展現「建表 → 回溯」雙階段結構。理解 c 與 b 矩陣的語意,是掌握序列比對類演算法的關鍵。生產環境長序列建議使用 Hirschberg 算法 (O(n) 空間) 或 C 擴充庫。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved