查找字符串数组的最长公共子字符串

时间:2017-08-05 17:56:17

标签: ios algorithm swift3 lcs longest-substring

在我的Swift 3.0应用程序中,我想通过找到6到12个字符串的最长公共子字符串来确定某个东西的最佳名称。

示例字符串:

ON/OFF office lights
DIM office lights
VALUE office lights
FB office lights
FB VALUE office lights

期望的输出:

office lights

对于最长的子序列,我遇到了多个StackOverflow答案,但无法根据我的需要调整其中任何一个。

非常感谢任何帮助!

1 个答案:

答案 0 :(得分:3)

我转换了 Java & C ++ 代码 Swift 3 ,收集自 GeeksForGeeks Longest Common Subsequence& Longest Common Substring

有效!

class LongestCommon
{
    // Returns length of LCS for X[0..m-1], Y[0..n-1]
    private static func lcSubsequence(_ X : String  , _ Y : String  ) -> String
    {
        let m = X.characters.count
        let n = Y.characters.count

        var L = Array(repeating: Array(repeating: 0, count: n + 1 ) , count: m + 1)
        // Following steps build L[m+1][n+1] in bottom up fashion. Note
        // that L[i][j] contains length of LCS of X[0..i-1] and Y[0..j-1]
        for i in stride(from: 0, through: m, by: 1)
        {
            for j in stride(from: 0, through: n, by: 1)
            {
                if i == 0 || j == 0
                {
                    L[i][j] = 0;
                }
                else if X[X.index( X.startIndex , offsetBy: (i - 1) )] == Y[Y.index( Y.startIndex , offsetBy: (j - 1) )]
                {
                    L[i][j] = L[i-1][j-1] + 1
                }
                else
                {
                   L[i][j] = max(L[i-1][j], L[i][j-1])
                }
            }

        }

        // Following code is used to print LCS
        var index = L[m][n]
        // Create a character array to store the lcs string
        var lcs = ""
        // Start from the right-most-bottom-most corner and
        // one by one store characters in lcs[]
        var i = m
        var j = n

        while (i > 0 && j > 0)
        {
            // If current character in X[] and Y are same, then
            // current character is part of LCS
            if X[X.index( X.startIndex , offsetBy: (i - 1) )] == Y[Y.index( Y.startIndex , offsetBy: (j - 1) )]
            {
                lcs.append(X[X.index( X.startIndex , offsetBy: (i - 1) )])
                i-=1
                j-=1
                index-=1
            }
            // If not same, then find the larger of two and
            // go in the direction of larger value
            else if (L[i-1][j] > L[i][j-1])
            {
                i-=1
            }
            else
            {
                j-=1
            }
        }

        // return the lcs
        return String(lcs.characters.reversed())
    }

    // Returns length of LCS for X[0..m-1], Y[0..n-1]
    private static func lcSubstring(_ X : String  , _ Y : String  ) -> String
    {
        let m = X.characters.count
        let n = Y.characters.count

        var L = Array(repeating: Array(repeating: 0, count: n + 1 ) , count: m + 1)
        var result : (length : Int, iEnd : Int, jEnd : Int) = (0,0,0)
        // Following steps build L[m+1][n+1] in bottom up fashion. Note
        // that L[i][j] contains length of LCS of X[0..i-1] and Y[0..j-1]
        for i in stride(from: 0, through: m, by: 1)
        {
            for j in stride(from: 0, through: n, by: 1)
            {
                if i == 0 || j == 0
                {
                    L[i][j] = 0;
                }
                else if X[X.index( X.startIndex , offsetBy: (i - 1) )] == Y[Y.index( Y.startIndex , offsetBy: (j - 1) )]
                {
                    L[i][j] = L[i-1][j-1] + 1

                    if result.0 < L[i][j]
                    {
                        result.length = L[i][j]
                        result.iEnd = i
                        result.jEnd = j
                    }
                }
                else
                {
                    L[i][j] = 0 //max(L[i-1][j], L[i][j-1])
                }
            }

        }

        // Following code is used to print LCS


        let lcs = X.substring(with: X.index(X.startIndex, offsetBy: result.iEnd-result.length)..<X.index(X.startIndex, offsetBy: result.iEnd))

        // return the lcs
        return lcs
    }

    // driver program

    class func subsequenceOf(_ strings : [String] ) -> String
    {
        var answer = strings[0] // For on string answer is itself

        for i in stride(from: 1, to: strings.count, by: 1)
        {
            answer = lcSubsequence(answer,strings[i])
        }
        return answer
    }

    class func substringOf(_ strings : [String] ) -> String
    {
        var answer = strings[0] // For on string answer is itself

        for i in stride(from: 1, to: strings.count, by: 1)
        {
            answer = lcSubstring(answer,strings[i])
        }
        return answer
    }



}

用法:

let strings = ["ON/OFF office lights",
                       "DIM office lights",
                       "VALUE office lights",
                       "FB office lights",
                       "FB VALUE office lights"]
print(LongestCommon.subsequenceOf(strings))
print(LongestCommon.substringOf(strings))