Gần đây tôi đã triển khai thuật toán khoảng cách Damerau-Levenshtein từ mã giả trên Wikipedia. Tôi không thể tìm thấy bất kỳ lời giải thích chính xác cách thức hoạt động và giả sử dụng tên biến hoàn toàn không đủ thông tin như DA
, DB
, i1
, và j1
khiến tôi gãi đầu của tôi.
Đây là triển khai của tôi trong Python: https://gist.github.com/badocelot/5327337
Việc triển khai Python giúp tôi duyệt qua chương trình và tìm hiểu điều gì đang xảy ra, đổi tên các biến thành các tên hữu ích hơn. Tôi đã đủ quen thuộc với phương pháp Wagner-Fischer để tính toán khoảng cách Levenshtein mà tôi có một khung tham chiếu.
Có nguy cơ bị kéo dài quá mức, đây là cách tôi hiểu Damerau-Levenshtein:
Các biến bí ẩn:
DA
(last_row
trong mã của tôi) là một loại bản đồ giữ hàng cuối cùng mà mỗi phần tử được nhìn thấy; trong mã của tôi đó là một từ điển Python thực tếDB
(last_match_col
) giữ cột cuối cùng trong đó chữ cáib
khớp với chữ cái tronga
hàng hiện tạii1
(last_matching_row
) là số hàng từDA
cho chữ cái hiện tại trongb
j1
chỉ là một bản sao của giá trị củaDB
/last_match_col
trước khi nó có khả năng được cập nhật; trong mã của tôi, tôi vừa di chuyển nơilast_match_col
được cập nhật và loại bỏ biến này
Chi phí chuyển vị:
H[i1][j1] + (i-i1-1) + 1 + (j-j1-1)
đang tính toán chi phí hoán đổi ký tự hiện tại b
với ký tự cuối cùng b
được biết là trong a
(trận đấu cuối cùng), coi tất cả các ký tự ở giữa là bổ sung hoặc xóa.
Các thành phần của chi phí:
H[i1][j1]
hoàn nguyên chi phí cơ bản về điểm trong các tính toán trước khi chuyển vị, vì việc tìm kiếm một chuyển vị làm mất hiệu lực công việc trước đó(i-i1-1)
là khoảng cách giữa hàng hiện tại và hàng cuối cùng khớp với ký tự hiện tại, là số lần xóa sẽ được yêu cầu(j-j1-1)
là khoảng cách giữa cột hiện tại và cột cuối cùng có khớp, là số lần bổ sung- Phần phụ
+ 1
chỉ là chi phí chuyển vị
Nếu phân tích này không chính xác, tôi rất muốn biết mình đã sai ở đâu. Như tôi đã nói, tôi không thể tìm thấy bất kỳ lời giải thích chi tiết nào về cách thuật toán hoạt động trực tuyến.
Phiên bản cải tiến?
Tuy nhiên, đã nhận ra rằng tôi nhận ra rằng bằng cách tính chi phí cho cả bổ sung và xóa giữa các chữ cái chuyển đổi dường như là thiếu sót: một bổ sung và một xóa tương đương với một sự thay thế, điều này không kiểm tra được.
Nếu tất cả đều đúng, giải pháp sẽ không đáng kể: chi phí của các chữ cái giữa các chữ cái được chuyển đổi sẽ cao hơn các bổ sung và xóa: chuyển đổi càng nhiều thành thay thế càng tốt và thêm vào bất kỳ bổ sung hoặc xóa nào.
Vì vậy, chi phí sẽ là:
H[i1][j1] + max((i-i1-1), (j-j1-1)) + 1
Đây là mã của tôi cho phiên bản này: https://gist.github.com/badocelot/5327427
Từ một số thử nghiệm đơn giản, điều này có vẻ đúng. Ví dụ: "abcdef" -> "abcfad" cho khoảng cách chỉnh sửa là 2 (hoán đổi "d" và "f", thay đổi "e" thành "a"), trong khi thuật toán ban đầu cho khoảng cách 3 (ba lần cuối các chữ cái là sự thay thế, hoặc 1 chuyển vị + 1 phép cộng + 1 lần xóa).
Bây giờ, tôi không thể là người đầu tiên nghĩ về điều này. Vậy tại sao tôi không chạy qua nó? Có phải tôi đã không tìm kiếm đủ lâu? Hoặc có một số lỗ hổng tinh tế ngăn cản điều này thực sự hoạt động?