字符串处理算法

本文介绍了三种字符串搜索算法:KMP算法通过部分匹配表进行高效匹配,Boyer-Moore算法利用坏字符和好后缀规则,Rabin-Karp算法则借助哈希函数加速比较。示例代码展示了它们在Java中的应用。
摘要由CSDN通过智能技术生成

1、KMP算法:

package com.arithmetic.stringprocessing;
//KMP算法,通过kmp方法在源字符串中查找模式字符串,并返回匹配的位置。
//computeLPS方法用于计算模式字符串的部分匹配表(Longest Proper Prefix which is also Suffix)。
//示例中,输入的目标字符串为text,模式字符串为pattern,输出结果为匹配的位置。如果匹配失败,返回-1。
public class KMPAlgorithmDemo {
    public static int kmp(String text, String pattern) {
    	
        int n = text.length();
        
        int m = pattern.length();
        
        // 构建模式字符串的部分匹配表
        int[] lps = computeLPS(pattern);
        
        int i = 0;  // 目标字符串的索引
        
        int j = 0;  // 模式字符串的索引
        
        while (i < n) {
            if (text.charAt(i) == pattern.charAt(j)) {
                i++;
                j++;
                
                if (j == m) {
                    // 匹配成功,返回匹配位置
                    return i - j;
                }
            } else {
                if (j != 0) {
                    j = lps[j - 1];
                } else {
                    i++;
                }
            }
        }
        
        // 匹配失败,返回-1
        return -1;
    }
    
    private static int[] computeLPS(String pattern) {
        int m = pattern.length();
        int[] lps = new int[m];
        int len = 0;  // 最长相等的前缀后缀长度
        int i = 1;
        
        while (i < m) {
            if (pattern.charAt(i) == pattern.charAt(len)) {
                len++;
                lps[i] = len;
                i++;
            } else {
                if (len != 0) {
                    len = lps[len - 1];
                } else {
                    lps[i] = 0;
                    i++;
                }
            }
        }
        
        return lps;
    }
    
    public static void main(String[] args) {
        String text = "ABABDABACDABABCABAB";
        String pattern = "ABABCABAB";
        int index = kmp(text, pattern);
        
        if (index == -1) {
            System.out.println("Pattern not found!");
        } else {
            System.out.println("Pattern found at index " + index);
        }
    }
}

2、Boyer-Moore算法:

package com.arithmetic.stringprocessing;
import java.util.Arrays;
//Boyer-Moore算法,通过boyerMoore方法在目标字符串中查找模式字符串,并返回匹配的位置。
//在实现中,使用badChar数组构建坏字符规则,使用suffix数组构建好后缀规则。
//输入的目标字符串text,模式字符串为pattern,输出结果为匹配的位置。如果匹配失败,返回-1。
public class BoyerMooreAlgorithmDemo {
	
    private static final int NUM_OF_CHARS = 256;
    
    public static int boyerMoore(String text, String pattern) {
        int n = text.length();
        int m = pattern.length();
        
        if (m == 0) {
            return 0;
        }
        
        int[] badChar = new int[NUM_OF_CHARS];
        
        // 初始化坏字符表
        Arrays.fill(badChar, -1);
        for (int i = 0; i < m; i++) {
            badChar[pattern.charAt(i)] = i;
        }
        
        int[] suffix = new int[m];
        char[] patternChars = pattern.toCharArray();
        computeSuffix(patternChars, suffix);
        
        int i = 0;  // 目标字符串的索引
        while (i <= n - m) {
            int j = m - 1;// 模式字符串的索引
            
            while (j >= 0 && patternChars[j] == text.charAt(i + j)) {
                j--;
            }
            
            if (j == -1) {
                // 匹配成功,返回匹配位置
                return i;
            } else {
                // 坏字符规则
                int charIndex = text.charAt(i + j);
                i += Math.max(1, j - badChar[charIndex]);
                
                // 好后缀规则
                if (j < m - 1) {
                    int x = j + 1;
                    int shift = 0;
                    
                    if (suffix[x] != -1) {
                        shift = x - suffix[x] + 1;
                    } else {
                        while (x >= 0 && suffix[x] == -1) {
                            x--;
                        }
                        
                        if (x >= 0) {
                            shift = x + 1;
                        }
                    }
                    
                    i += shift;
                }
            }
        }
        
        // 匹配失败,返回-1
        return -1;
    }
    
    private static void computeSuffix(char[] pattern, int[] suffix) {
        int m = pattern.length;
        suffix[m - 1] = m;
        
        int f = 0;  // 前缀的起始位置
        
        for (int i = m - 2; i >= 0; i--) {
            while (f > 0 && pattern[f] != pattern[i + 1]) {
                f = suffix[f] - 1;
            }
            
            if (pattern[f] == pattern[i + 1]) {
                f--;
            }
            
            suffix[i] = f;
        }
    }
    
    public static void main(String[] args) {
        String text = "ABAAABCD";
        String pattern = "ABC";
        
        int index = boyerMoore(text, pattern);
        if (index == -1) {
            System.out.println("Pattern not found!");
        } else {
            System.out.println("Pattern found at index " + index);
        }
    }
}

3、Rabin-Karp算法:

package com.arithmetic.stringprocessing;
import java.util.ArrayList;
import java.util.List;
//Rabin-Karp算法使用哈希函数来比较模式串和文本串的哈希值,进而确定是否需要比较子串的字符。
//这种方法能够在平均情况下减少比较次数,从而提高匹配效率。
public class RabinKarpAlgorithmDemo {

    private static final int PRIME = 101;
    private static final int RADIX = 256;
   //rabinKarpSearch方法,主要算法逻辑在这个方法中。它接受文本字符串和模式串作为输入,并返回一个包含匹配位置的整数列表。
    public static List<Integer> rabinKarpSearch(String text, String pattern) {
        List<Integer> matches = new ArrayList<>();

        int n = text.length();
        int m = pattern.length();

        long patternHash = calculateHash(pattern, m, PRIME);
        long textHash = calculateHash(text, m, PRIME);

        for (int i = 0; i <= n - m; i++) {
            if (patternHash == textHash && isPatternMatch(text, pattern, i)) {
                matches.add(i);
            }

            if (i < n - m) {
                textHash = recalculateHash(text, i, i + m, textHash, m, PRIME);
            }
        }

        return matches;
    }
     //calculateHash方法,用于计算字符串的哈希值。它采用Horner's rule和mod运算来避免大数运算。
    private static long calculateHash(String str, int len, int prime) {
        long hashValue = 0;
        for (int i = 0; i < len; i++) {
            hashValue = (hashValue * RADIX + str.charAt(i)) % prime;
        }
        return hashValue;
    }
  //recalculateHash方法,用于在滑动窗口中重新计算哈希值。它减去旧索引位置字符的贡献,并加上新索引位置字符的贡献。
  //通过mod运算和处理负值来确保哈希值的范围在0到prime-1之间。
    private static long recalculateHash(String str, int oldIndex, int newIndex, long oldHash, int patternLen, int prime) {
        long newHash = (oldHash - (str.charAt(oldIndex) * (long) Math.pow(RADIX, patternLen - 1)) % prime) % prime;
        newHash = (newHash * RADIX + str.charAt(newIndex)) % prime;
        if (newHash < 0) {
            newHash += prime;
        }
        return newHash;
    }
    //isPatternMatch方法:用于检查文本字符串中的子串是否与模式串匹配。
    private static boolean isPatternMatch(String text, String pattern, int index) {
        for (int i = 0; i < pattern.length(); i++) {
            if (text.charAt(index + i) != pattern.charAt(i)) {
                return false;
            }
        }
        return true;
    }
      //main方法:定义一个示例,使用示例文本字符串和模式串来演示Rabin-Karp算法的使用。它输出匹配位置或提示未找到匹配。
    public static void main(String[] args) {
        String text = "ABABDABACDABABCABAB";
        String pattern = "ABABCABAB";

        List<Integer> matches = rabinKarpSearch(text, pattern);
        if (matches.isEmpty()) {
            System.out.println("No matches found");
        } else {
            System.out.println("Pattern found at indexes: " + matches);
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值