在字符串中查找重复序列

时间:2015-06-28 00:41:15

标签: vb.net string algorithm

我想在VB.Net中的字符串中找到重复序列,如:

Dim test as String =“EDCRFVTGBEDCRFVTGBEDCRFVTGBEDCRFVTGBEDCRFVTGBEDCRFVTGBEDCRFVTGB”

我希望程序检测重复序列,以防EDCRFVTGB并计算重复次数。我的问题是找到字符串中的重复序列,我搜索了几种方法来做,但我没有得到解决方案,我尝试了快速排序算法,重复算法,但其中一些不能用于字符串。

我虽然创建了子串并检查它们是否存在于字符串中,但我不知道如何获取子字符串,因为字符串上没有模式,字符串中也可能没有重复序列

4 个答案:

答案 0 :(得分:1)

首先检查目标字符串的一半是否重复两次。如果没有,检查字符串的三分之一是否重复三次。如果没有,检查字符串的四分之一是否重复四次。这样做直到找到匹配的序列。跳过商数不是整数的任何除数,使其表现更好。此代码应该可以解决这个问题并填写此描述无法澄清的任何空白:

Public Function DetermineSequence(ByVal strTarget As String) As String

    Dim strSequence As String = String.Empty

    Dim intLengthOfTarget As Integer = strTarget.Length

    'Check for a valid Target string.
    If intLengthOfTarget > 2 Then

        'Try 1/2 of Target, 1/3 of Target, 1/4 of Target, etc until sequence is found.
        Dim intCursor As Integer = 2

        Do Until strSequence.Length > 0 OrElse intCursor = intLengthOfTarget

            'Don't even test the string if its length is not a divisor (to an Integer) of the length of the target String.
            If IsDividendDivisibleByDivisor(strTarget.Length, intCursor) Then

                'Get the possible sequence.
                Dim strPossibleSequence As String = strTarget.Substring(0, (intLengthOfTarget / intCursor))

                'See if this possible sequence actually is the repeated String.
                If IsPossibleSequenceRepeatedThroughoutTarget(strPossibleSequence, strTarget) Then

                    'The repeated sequence has been found.
                    strSequence = strPossibleSequence

                End If

            End If

            intCursor += 1

        Loop

    End If

    Return strSequence

End Function

Private Function IsDividendDivisibleByDivisor(ByVal intDividend As Integer, ByVal intDivisor As Integer) As Boolean

    Dim bolDividendIsDivisbleByDivisor As Boolean = False

    Dim intOutput As Integer

    If Integer.TryParse((intDividend / intDivisor), intOutput) Then

        bolDividendIsDivisbleByDivisor = True

    End If

    Return bolDividendIsDivisbleByDivisor

End Function

Private Function IsPossibleSequenceRepeatedThroughoutTarget(ByVal strPossibleSequence As String, ByVal strTarget As String) As Boolean

    Dim bolPossibleSequenceIsRepeatedThroughoutTarget As Boolean = False

    Dim intLengthOfTarget As Integer = strTarget.Length
    Dim intLengthOfPossibleSequence As Integer = strPossibleSequence.Length

    Dim bolIndicatorThatPossibleSequenceIsCertainlyNotRepeated As Boolean = False

    Dim intCursor As Integer = 1

    Do Until (intCursor * intLengthOfPossibleSequence) = strTarget.Length OrElse bolIndicatorThatPossibleSequenceIsCertainlyNotRepeated

        If strTarget.Substring((intCursor * intLengthOfPossibleSequence), intLengthOfPossibleSequence) <> strPossibleSequence Then

            bolIndicatorThatPossibleSequenceIsCertainlyNotRepeated = True

        End If

        intCursor += 1

    Loop

    If Not bolIndicatorThatPossibleSequenceIsCertainlyNotRepeated Then

        bolPossibleSequenceIsRepeatedThroughoutTarget = True

    End If

    Return bolPossibleSequenceIsRepeatedThroughoutTarget

End Function

答案 1 :(得分:1)

这是一个示例,它允许您指定序列的最小和最大长度,并返回一个名为sequence的自定义类的列表,其中有多个匹配项。序列类将包含找到的模式和模式发生的索引列表。

enter image description here

Option Strict On
Option Explicit On
Option Infer Off
Public Class Form1
    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click

        ListView1.Items.Clear()
        ListView1.Columns.Clear()
        ListView1.Columns.Add("Sequence")
        ListView1.Columns.Add("Indexes of occurrence")
        Dim sequences As List(Of Sequence) = DetectSequences("EDCRFVTGBEDCRFVTGBEDCRFVTGBEDCRFVTGBEDCRFVTGBEDCRFVTGBEDCRFVTGB")
        For Each s As Sequence In sequences
            Dim item As New ListViewItem(s.Sequence)
            item.Tag = s
            item.SubItems.Add(s.IndexesToString)
            ListView1.Items.Add(item)
        Next
        ListView1.AutoResizeColumns(ColumnHeaderAutoResizeStyle.HeaderSize)
    End Sub
    Function DetectSequences(s As String, Optional minLength As Integer = 5, Optional MaxLength As Integer = 8) As List(Of Sequence)
        Dim foundPatterns As New List(Of String)
        Dim foundSequences As New List(Of Sequence)
        Dim potentialPattern As String = String.Empty, potentialMatch As String = String.Empty
        For start As Integer = 0 To s.Length - 1
            For length As Integer = 1 To s.Length - start
                potentialPattern = s.Substring(start, length)
                If potentialPattern.Length < minLength Then Continue For
                If potentialPattern.Length > MaxLength Then Continue For
                If foundPatterns.IndexOf(potentialPattern) = -1 Then
                    foundPatterns.Add(potentialPattern)
                End If
            Next
        Next
        For Each pattern As String In foundPatterns
            Dim sequence As New Sequence With {.Sequence = pattern}
            For start As Integer = 0 To s.Length - pattern.Length
                Dim length As Integer = pattern.Length
                potentialMatch = s.Substring(start, length)
                If potentialMatch = pattern Then
                    sequence.Indexes.Add(start)
                End If
            Next
            If sequence.Indexes.Count > 1 Then foundSequences.Add(sequence)
        Next
        Return foundSequences
    End Function
    Public Class Sequence
        Public Sequence As String = ""
        Public Indexes As New List(Of Integer)
        Public Function IndexesToString() As String
            Dim sb As New System.Text.StringBuilder
            For i As Integer = 0 To Indexes.Count - 1
                If i = Indexes.Count - 1 Then
                    sb.Append(Indexes(i).ToString)
                Else
                    sb.Append(Indexes(i).ToString & ", ")
                End If
            Next
            Return sb.ToString
        End Function
    End Class
    Private Sub ListView1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ListView1.SelectedIndexChanged
        If ListView1.SelectedItems.Count = 0 Then Exit Sub
        RichTextBox1.Clear()
        RichTextBox1.Text = "EDCRFVTGBEDCRFVTGBEDCRFVTGBEDCRFVTGBEDCRFVTGBEDCRFVTGBEDCRFVTGB"
        Dim selectedSequence As Sequence = DirectCast(ListView1.SelectedItems(0).Tag, Sequence)
        For Each i As Integer In selectedSequence.Indexes
            RichTextBox1.SelectionStart = i
            RichTextBox1.SelectionLength = selectedSequence.Sequence.Length
            RichTextBox1.SelectionBackColor = Color.Red
        Next
    End Sub
End Class

答案 2 :(得分:0)

你知道字符串的起源吗? 你知道它有多久了吗?

直截了当的算法是:

for each character index i
    for each character index after that j
        compare substring(i, j-i) to substring(j, j-i)
        if equal, record as a found repeating substring

有一些优化,比如知道字符串不能超出字符串的末尾(j的上限),只查找比你刚才找到的字符串更长的子字符串。

这不是超级有效的(N平方),但是一个相关的广义问题(“编辑距离”)也不比N平方好,所以你去。

答案 3 :(得分:-1)

这是一种算法,它以这样的方式生成所有重复序列,使得它们按长度和第一次出现排序。它基于一个简单的想法:在一个句子中找到一个单词两次,相同的起始字母必须出现两次。

带有一些解释的Java代码(算法保持不变),它将输出交织的重复,例如BANANA =&gt; A,N,AN,NA,ANA(1,3),你可以消除一个索引,如果前一个的距离小于字符串长度,在这个算法中纠正它(在代码下面是一个样本运行,应该更好地解释一下):

public List<String> getRepetitions(String string) {
   List<String> repetitions = new ArrayList<String>();
   Map<String, List<Integer>> rep = new HashMap<String, List<Integer>>(), repOld;
   // init rep, add start position of all single character length strings
   for (int i = 0; i < string.length(); i++) {
      String s = string.substring(i, i + 1); // startIndex inclusive, endIndex exclusive
      if (rep.containsKey(s)) {
         rep.get(s).add(new Integer(i));
      } else {
         List<Integer> l = new ArrayList<Integer>();
         l.add(new Integer(i));
         rep.put(l);
      }
   }
   // eliminate those with no repetitions and add the others to the solution
   for (Map.Entry<String, Integer> e : rep.entrySet()) {
      if (e.getValue().size() < 2) {
         rep.remove(e.getKey());
      } else {
         repetitions.add(e.getKey());
      }
   }
   for (int len = 1; rep.size() > 0; len++) {
      repOld = rep;
      rep = new HashMap<String, List<Integer>>();
      for (Map.EntrySet<String, List<Integer>> e : repOld.entrySet()) {
         for (Integer i : e.getValue()) { // for all start indices
            if (i.intValue() + len + 1 >= string.length())
               break;
            String s = e.getKey() + string.charAt(i.intValue() + len + 1);
            if (rep.containsKey(s)) {
               rep.get(s).add(i);
            } else {
               List<Integer> l = new ArrayList<Integer>();
               l.add(i);
               rep.put(l);
            }
         } 
      }
      // eliminate repetitions and add to solution
      for (Map.Entry<String, Integer> e : rep.entrySet()) {
         if (e.getValue().size() < 2) {
            rep.remove(e.getKey());
         } else {
            repetitions.add(e.getKey());
         }
      }
   }
   return repetitions; // ordered by length, so last = longest
}

BANANA的样本运行:

  1. 将单个字母添加到rep =&gt; B - &gt; [0],A - &gt; [1,3,5],N - > [2,4]
  2. 消除少于2次出现的那些(B),将其他人添加到溶液中(A,N)
  3. 将以下字母添加到剩余的出现次数(创建新的rep):AN - &gt; [1,3],NA - > [2,4]
  4. 消除( - )并添加(AN,NA)
  5. 重复步骤3和4:ANA - > [1,3]
  6. 循环rep中的
  7. 将变为空并且算法已完成