hirschbergDiff recursively computes the LCS-based diff in linear space. The algorithm splits seq1 in half, finds the optimal split point in seq2 using forward and backward LCS score rows, then recurses on each half. At each recursion level only O(len(seq2)) extra space is used.
(seq1, seq2 []string)
| 51 | // using forward and backward LCS score rows, then recurses on each half. |
| 52 | // At each recursion level only O(len(seq2)) extra space is used. |
| 53 | func hirschbergDiff(seq1, seq2 []string) []difflib.DiffRecord { |
| 54 | n, m := len(seq1), len(seq2) |
| 55 | |
| 56 | if n == 0 { |
| 57 | result := make([]difflib.DiffRecord, m) |
| 58 | for i, s := range seq2 { |
| 59 | result[i] = difflib.DiffRecord{Payload: s, Delta: difflib.RightOnly} |
| 60 | } |
| 61 | return result |
| 62 | } |
| 63 | if m == 0 { |
| 64 | result := make([]difflib.DiffRecord, n) |
| 65 | for i, s := range seq1 { |
| 66 | result[i] = difflib.DiffRecord{Payload: s, Delta: difflib.LeftOnly} |
| 67 | } |
| 68 | return result |
| 69 | } |
| 70 | if n == 1 { |
| 71 | return singleRowDiff(seq1[0], seq2) |
| 72 | } |
| 73 | |
| 74 | mid := n / 2 |
| 75 | |
| 76 | forward := lcsLift(seq1[:mid], seq2) |
| 77 | backward := lcsLiftSuffix(seq1[mid:], seq2) |
| 78 | |
| 79 | splitJ := 0 |
| 80 | maxScore := -1 |
| 81 | for j := 0; j <= m; j++ { |
| 82 | score := forward[j] + backward[j] |
| 83 | if score > maxScore { |
| 84 | maxScore = score |
| 85 | splitJ = j |
| 86 | } |
| 87 | } |
| 88 | |
| 89 | left := hirschbergDiff(seq1[:mid], seq2[:splitJ]) |
| 90 | right := hirschbergDiff(seq1[mid:], seq2[splitJ:]) |
| 91 | |
| 92 | return append(left, right...) |
| 93 | } |
| 94 | |
| 95 | // singleRowDiff handles the base case where seq1 has exactly one element. |
| 96 | // It matches difflib.Diff's behavior which prefers LeftOnly and matches |
no test coverage detected