Go: 最长公共子序列打印结果数组

huangapple go评论115阅读模式
英文:

Go : longest common subsequence to print result array

问题

我已经实现了最长公共子序列算法,并且得到了最长子序列的正确答案,但是无法找到打印最长公共子序列的方法。

也就是说,我成功地得到了最长公共子序列数组的长度,但是我想打印出最长子序列。

这段代码的 Playground 在这里:

http://play.golang.org/p/0sKb_OARnf

/*
X = BDCABA
Y = ABCBDAB => 最长公共子序列是 B C B

动态规划方法:O(n)
*/

package main
import "fmt"

func Max(more ...int) int {
  max_num := more[0]
  for _, elem := range more {
    if max_num < elem {
      max_num = elem
    }
  }
  return max_num
}

func Longest(str1, str2 string) int {
  len1 := len(str1)
  len2 := len(str2)

  //在 C++ 中,
  //int tab[m + 1][n + 1];
  //tab := make([][100]int, len1+1)

  tab := make([][]int, len1+1)
  for i := range tab {
    tab[i] = make([]int, len2+1)
  }

  i, j := 0, 0
  for i = 0; i <= len1; i++ {
    for j = 0; j <= len2; j++ {
      if i == 0 || j == 0 {
        tab[i][j] = 0
      } else if str1[i-1] == str2[j-1] {
        tab[i][j] = tab[i-1][j-1] + 1
        if i < len1 {
          fmt.Printf("%c", str1[i])
        }
      } else {
        tab[i][j] = Max(tab[i-1][j], tab[i][j-1])
      }
    }
  }
  fmt.Println()
  return tab[len1][len2]
}

func main() {
  str1 := "AGGTABTABTABTAB"
  str2 := "GXTXAYBTABTABTAB"
  fmt.Println(Longest(str1, str2))
  //实际的最长公共子序列:GTABTABTABTAB
  //GGGGGTAAAABBBBTTTTAAAABBBBTTTTAAAABBBBTTTTAAAABBBB
  //13

  str3 := "AGGTABGHSRCBYJSVDWFVDVSBCBVDWFDWVV"
  str4 := "GXTXAYBRGDVCBDVCCXVXCWQRVCBDJXCVQSQQ"
  fmt.Println(Longest(str3, str4))
  //实际的最长公共子序列:?
  //GGGTTABGGGHHRCCBBBBBBYYYJSVDDDDDWWWFDDDDDVVVSSSSSBCCCBBBBBBVVVDDDDDWWWFWWWVVVVVV
  //14
}

当我尝试在 tab 更新时打印子序列时,结果是重复的。
我想要打印出类似于 "GTABTABTABTAB" 的结果,对于 str1 和 str2

提前感谢。

英文:

I have implemented Longest Common Subsequence algorithm and getting the right answer for longest but cannot figure out the way to print out what makes up the longest common subsequence.

That is, I succeeded to get the length of longest commond subsequence array but I want to print out the longest subsequence.

The Playground for this code is here

http://play.golang.org/p/0sKb_OARnf

/*
X = BDCABA
Y = ABCBDAB =&gt; Longest Comman Subsequence is B C B

Dynamic Programming method : O ( n )
*/

package main
import &quot;fmt&quot;

func Max(more ...int) int {
  max_num := more[0]
  for _, elem := range more {
    if max_num &lt; elem {
      max_num = elem
    }
  }
  return max_num
}

func Longest(str1, str2 string) int {
  len1 := len(str1)
  len2 := len(str2)

  //in C++,
  //int tab[m + 1][n + 1];
  //tab := make([][100]int, len1+1)

  tab := make([][]int, len1+1)
  for i := range tab {
    tab[i] = make([]int, len2+1)
  }

  i, j := 0, 0
  for i = 0; i &lt;= len1; i++ {
    for j = 0; j &lt;= len2; j++ {
      if i == 0 || j == 0 {
        tab[i][j] = 0
      } else if str1[i-1] == str2[j-1] {
        tab[i][j] = tab[i-1][j-1] + 1
        if i &lt; len1 {
          fmt.Printf(&quot;%c&quot;, str1[i])
        }
      } else {
        tab[i][j] = Max(tab[i-1][j], tab[i][j-1])
      }
    }
  }
  fmt.Println()
  return tab[len1][len2]
}

func main() {
  str1 := &quot;AGGTABTABTABTAB&quot;
  str2 := &quot;GXTXAYBTABTABTAB&quot;
  fmt.Println(Longest(str1, str2))
  //Actual Longest Common Subsequence: GTABTABTABTAB
  //GGGGGTAAAABBBBTTTTAAAABBBBTTTTAAAABBBBTTTTAAAABBBB
  //13

  str3 := &quot;AGGTABGHSRCBYJSVDWFVDVSBCBVDWFDWVV&quot;
  str4 := &quot;GXTXAYBRGDVCBDVCCXVXCWQRVCBDJXCVQSQQ&quot;
  fmt.Println(Longest(str3, str4))
  //Actual Longest Common Subsequence: ?
  //GGGTTABGGGHHRCCBBBBBBYYYJSVDDDDDWWWFDDDDDVVVSSSSSBCCCBBBBBBVVVDDDDDWWWFWWWVVVVVV
  //14
}

When I try to print out the subsequence when the tab gets updates, the outcome is duplicate.
I want to print out something like "GTABTABTABTAB" for the str1 and str2

Thanks in advance.

答案1

得分: 0

编辑:看起来我在回答这个问题时有点过早。在最长公共子序列的维基百科页面上,他们给出了一段伪代码,用于在计算出最长公共子序列后打印出来。我会尽快在这里放上一个go的实现。

旧的无效答案

你忘记在将字符注册为子序列的一部分后继续移动。

下面的代码应该可以工作。看一下fmt.Printf("%c", srt1[i])行后面的两行代码。

playground链接

/*
X = BDCABA
Y = ABCBDAB => 最长公共子序列是 B C B

动态规划方法:O(n)
*/

package main

import "fmt"

func Max(more ...int) int {
    max_num := more[0]
     for _, elem := range more {
        if max_num < elem {
            max_num = elem
        }
    }
    return max_num
}

func Longest(str1, str2 string) int {
    len1 := len(str1)
    len2 := len(str2)

    //在C++中,
    //int tab[m + 1][n + 1];
    //tab := make([][100]int, len1+1)

    tab := make([][]int, len1+1)
    for i := range tab {
        tab[i] = make([]int, len2+1)
    }

    i, j := 0, 0
    for i = 0; i <= len1; i++ {
        for j = 0; j <= len2; j++ {
            if i == 0 || j == 0 {
                tab[i][j] = 0
            } else if str1[i-1] == str2[j-1] {
                tab[i][j] = tab[i-1][j-1] + 1
                if i < len1 {
                    fmt.Printf("%c", str1[i])
                                            //在两个序列中继续下一个字符
                    i++
                    j++
                }
            } else {
                tab[i][j] = Max(tab[i-1][j], tab[i][j-1])
            }
        }
    }
    fmt.Println()
    return tab[len1][len2]
}

func main() {
    str1 := "AGGTABTABTABTAB"
    str2 := "GXTXAYBTABTABTAB"
    fmt.Println(Longest(str1, str2))
    //实际最长公共子序列:GTABTABTABTAB
    //GGGGGTAAAABBBBTTTTAAAABBBBTTTTAAAABBBBTTTTAAAABBBB
    //13

    str3 := "AGGTABGHSRCBYJSVDWFVDVSBCBVDWFDWVV"
    str4 := "GXTXAYBRGDVCBDVCCXVXCWQRVCBDJXCVQSQQ"
    fmt.Println(Longest(str3, str4))
    //实际最长公共子序列:?
     //GGGTTABGGGHHRCCBBBBBBYYYJSVDDDDDWWWFDDDDDVVVSSSSSBCCCBBBBBBVVVDDDDDWWWFWWWVVVVVV
    //14
}
英文:

EDIT: It seems that I jumped the gun on answering this. On the Wikipedia page for Longest Common Subsequnce they give the pseudocode for printing out the LCS once it has been calculated. I'll put an implementation in go up here as soon as I have time for it.

Old invalid answer

You are forgetting to move along from a character once you have registered it as part of the subsequence.

The code below should work. Look at the two lines right after the fmt.Printf(&quot;%c&quot;, srt1[i]) line.

playground link

/*
X = BDCABA
Y = ABCBDAB =&gt; Longest Comman Subsequence is B C B

Dynamic Programming method : O ( n )
*/

package main

import &quot;fmt&quot;

func Max(more ...int) int {
    max_num := more[0]
     for _, elem := range more {
        if max_num &lt; elem {
            max_num = elem
        }
    }
    return max_num
}

func Longest(str1, str2 string) int {
    len1 := len(str1)
    len2 := len(str2)

    //in C++,
    //int tab[m + 1][n + 1];
    //tab := make([][100]int, len1+1)

    tab := make([][]int, len1+1)
    for i := range tab {
        tab[i] = make([]int, len2+1)
    }

    i, j := 0, 0
    for i = 0; i &lt;= len1; i++ {
        for j = 0; j &lt;= len2; j++ {
            if i == 0 || j == 0 {
                tab[i][j] = 0
            } else if str1[i-1] == str2[j-1] {
                tab[i][j] = tab[i-1][j-1] + 1
                if i &lt; len1 {
                    fmt.Printf(&quot;%c&quot;, str1[i])
                                            //Move on the the next character in both sequences
                    i++
                    j++
                }
            } else {
                tab[i][j] = Max(tab[i-1][j], tab[i][j-1])
            }
        }
    }
    fmt.Println()
    return tab[len1][len2]
}

func main() {
    str1 := &quot;AGGTABTABTABTAB&quot;
    str2 := &quot;GXTXAYBTABTABTAB&quot;
    fmt.Println(Longest(str1, str2))
    //Actual Longest Common Subsequence: GTABTABTABTAB
    //GGGGGTAAAABBBBTTTTAAAABBBBTTTTAAAABBBBTTTTAAAABBBB
    //13

    str3 := &quot;AGGTABGHSRCBYJSVDWFVDVSBCBVDWFDWVV&quot;
    str4 := &quot;GXTXAYBRGDVCBDVCCXVXCWQRVCBDJXCVQSQQ&quot;
    fmt.Println(Longest(str3, str4))
    //Actual Longest Common Subsequence: ?
     //GGGTTABGGGHHRCCBBBBBBYYYJSVDDDDDWWWFDDDDDVVVSSSSSBCCCBBBBBBVVVDDDDDWWWFWWWVVVVVV
    //14
}

huangapple
  • 本文由 发表于 2013年11月22日 21:13:14
  • 转载请务必保留本文链接:https://go.coder-hub.com/20145795.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定