Java 实现用于短文本大小的字符串搜索算法

Java 实现用于短文本大小的字符串搜索算法

在这个问题中,我们需要找到字符串中模式的索引。实现高效的文本搜索非常重要,以使用户能够轻松搜索大型文本数据库。例如,您正在Microsoft Word中撰写博客或在VSCode中编写代码,其中包含1 lakh以上的单词。如果搜索算法效率低下,搜索任何单词或句子时可能需要时间才能显示搜索结果。

我们将学习两种不同的方法来实现字符串搜索算法。一种是朴素方法,另一种是KMP算法。

问题描述 - 给定一个字符串str和不同长度的搜索值。我们需要找到给定字符串中搜索值的索引。

示例

输入

str = "welcome to Tutorialspoint for well organized tutorials and libraries!", 
searchValue = "wel";

输出

0, 30

解释: - 它打印出str中搜索值的起始位置。

输入:

str = "Apple is good! Apple is Awesome! Apples are amazing!", searchValue = 
"Apple is"

输出

0, 15

解释 - 在给定的字符串中,“Apple is”出现了两次。

输入

str = 'Hello! Are you fine?”, searchValue = “How”

输出

-1

解释 - 由于在字符串中找不到搜索值,因此打印-1。

方法1

这是一种天真的方法,我们将检查长度等于搜索值长度的每个子字符串以找到匹配的结果。

算法

步骤1 - 初始化长度变量和’matches’以存储匹配的总数。

步骤2 - 从0索引到(len_str – len_search)索引遍历字符串。

步骤3 - 使用另一个嵌套循环来遍历搜索模式。

步骤4 - 如果字符串中(p + q)索引处的字符和搜索值中第q个索引处的字符不匹配,则停止循环。

步骤5 - 如果q等于len_search,则增加匹配,并打印p值,因为我们找到了该模式。

步骤6 - 最后,如果match值等于0,则打印-1,因为我们在字符串中找不到任何搜索值。

代码

import java.io.*;
public class Main {
   // Function to find string matches
   public static void FindMatch(String str, String searchValue) {
      int len_str = str.length();
      int len_search = searchValue.length();
      int matches = 0;
      // Traverse the string
      for (int p = 0; p <= (len_str - len_search); p++) {
         int q;
         for (q = 0; q < len_search; q++) {
            if (str.charAt(p + q) != searchValue.charAt(q))
               break;
         }
         if (q == len_search) {
            matches++;
            System.out.println("Pattern position is : " + p);
         }
      }
      if (matches == 0)
         System.out.println("No Pattern Found in the given string!");
      else
         System.out.println("Total search patterns found in the string are = " + matches);
   }
   public static void main(String[] args) {
      String str = "welcome to Tutorialspoint for well organized tutorials and libraries!";
      String searchValue = "wel";
      FindMatch(str, searchValue);
   }
}

输出

Pattern position is : 0
Pattern position is : 30
Total search patterns found in the string are = 2

时间复杂度 - O(N*M),其中N是字符串长度,M是搜索值长度。

空间复杂度 - O(1),因为我们没有使用额外的空间。

方法2

KMP算法是由Knuth-Morris-Pratt发明的,它是一种非常高效的字符串搜索方法。KMP算法帮助我们避免在搜索模式时发生不必要的回溯。在朴素方法中,我们在每个长度为M的子字符串中进行搜索,但在这里我们不需要在给定的字符串中回溯。

我们将准备一个最长前缀数组,用于帮助我们进行高效的搜索。

算法

步骤1 - 在findMatch()函数中,定义所需变量和longest_pref_suff[]数组以存储最长前缀。

步骤2 - 执行processSuffPref()函数以填充最长前缀数组。

步骤2.1 - 在processSuffPref()函数中,将第一个元素初始化为0。还需定义prev_len并初始化为0,p初始化为1。

步骤2.2 - 迭代直到p小于search_len。如果搜索模式中第p个索引处的字符与prev_len索引处的字符相同,则增加prev_len和p的值。同时,在数组中插入prev_len的值。

步骤2.3 - 如果字符不匹配且prev_len不等于零,则通过longest_pref_suf[prev_len-1]更新其值。否则,更新数组中第p个索引处的值并增加’p’的值。

步骤3 - 在下一步中,将p和q初始化为0。此后,开始对字符串和模式进行迭代。

步骤4 - 如果search.charAt(q) str.charAt(p)为真,将p和q都增加1以前进。

步骤5 - 如果q search_len为真,则打印p – q,即搜索值的起始索引。同时,将q的值更新为longest_pref_suff[q-1]。

步骤6 - 如果q不等于search_len且str中索引p和搜索字符串中索引q的字符不相同,请按照以下步骤进行。

步骤7 - 如果q不为零,则更新q的值;否则,将p增加1。

代码

public class Main {
   public static void processSuffPref(String search, 
   int search_len, int longest_pref_suf[]) {
      // variable to store the length of the previous prefix
      int prev_len = 0;
      int p = 1;
      longest_pref_suf[0] = 0; // This is always 0
      while (p < search_len) {
         if (search.charAt(p) == search.charAt(prev_len)) {
            prev_len++;
            longest_pref_suf[p] = prev_len;
            p++;
         } else // If it doesn't match
         {
            if (prev_len != 0) {
               prev_len = longest_pref_suf[prev_len - 1];
            } else {
               longest_pref_suf[p] = prev_len;
               p++;
            }
         }
      }
   }

   public static void FindMatch(String str, String search) {
      // Initialize lengths
      int str_len = str.length();
      int search_len = search.length();
      // array to store longest prefix and suffix values
      int longest_pref_suff[] = new int[search_len];
      // calculate the longest prefix and suffix values
      processSuffPref(search, search_len, longest_pref_suff);
      int p = 0; // string index
      int q = 0; // search index
      while (p < str_len) {
// If characters at q index in str and p index in p match, increment both pointers
         if (search.charAt(q) == str.charAt(p)) {
            q++; p++;
         }
         if (q == search_len) {
            System.out.println("Index of search value is - " + (p - q));
            q = longest_pref_suff[q - 1];
         }
         // If a pattern is not found after q matches
         else if (p < str_len && search.charAt(q) != str.charAt(p)) {
            if (q != 0)
               q = longest_pref_suff[q - 1];
            else
               p = p + 1;
         }
      }
   }
   public static void main(String args[]) {
      String str = "welcome to Tutorialspoint for well organized tutorials and libraries!";
      String searchValue = "wel";
      FindMatch(str, searchValue);
   }
}

输出

Index of search value is - 0
Index of search value is - 30

时间复杂度 - O(N + M),因为在遍历字符串和模式时,我们不进行回溯。

空间复杂度 - O(M),因为我们存储了搜索模式的最长前缀。

程序员可以观察到第一种和第二种方法的时间复杂度的差异。第一种方法比第二种方法花费的时间要多M倍。KMP算法可以用于在包含数百万字的大文本中搜索模式。

Camera课程

Python教程

Java教程

Web教程

数据库教程

图形图像教程

办公软件教程

Linux教程

计算机教程

大数据教程

开发工具教程