字符串算法

# 字符串算法

# 📋 学习目标

  • 掌握字符串的基本操作
  • 理解字符串匹配算法
  • 学会字符串处理的常用技巧
  • 熟练解决字符串相关问题

# 🔤 基础操作

# 字符串反转

public String reverse(String s) {
    char[] chars = s.toCharArray();
    int left = 0, right = chars.length - 1;
    
    while (left < right) {
        char temp = chars[left];
        chars[left] = chars[right];
        chars[right] = temp;
        left++;
        right--;
    }
    
    return new String(chars);
}

# 回文判断

public boolean isPalindrome(String s) {
    int left = 0, right = s.length() - 1;
    
    while (left < right) {
        while (left < right && !Character.isLetterOrDigit(s.charAt(left))) {
            left++;
        }
        while (left < right && !Character.isLetterOrDigit(s.charAt(right))) {
            right--;
        }
        
        if (Character.toLowerCase(s.charAt(left)) != 
            Character.toLowerCase(s.charAt(right))) {
            return false;
        }
        
        left++;
        right--;
    }
    
    return true;
}

# 🔍 字符串匹配

# KMP算法

public 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 int kmpSearch(String text, String pattern) {
    int n = text.length();
    int m = pattern.length();
    int[] lps = computeLPS(pattern);
    
    int i = 0; // text的索引
    int j = 0; // pattern的索引
    
    while (i < n) {
        if (pattern.charAt(j) == text.charAt(i)) {
            i++;
            j++;
        }
        
        if (j == m) {
            return i - j; // 找到匹配
        } else if (i < n && pattern.charAt(j) != text.charAt(i)) {
            if (j != 0) {
                j = lps[j - 1];
            } else {
                i++;
            }
        }
    }
    
    return -1; // 未找到
}

# Rabin-Karp算法

public int rabinKarp(String text, String pattern) {
    int n = text.length();
    int m = pattern.length();
    int prime = 101;
    int patternHash = 0;
    int textHash = 0;
    int h = 1;
    
    // 计算h = pow(256, m-1) % prime
    for (int i = 0; i < m - 1; i++) {
        h = (h * 256) % prime;
    }
    
    // 计算模式串和文本第一个窗口的哈希值
    for (int i = 0; i < m; i++) {
        patternHash = (256 * patternHash + pattern.charAt(i)) % prime;
        textHash = (256 * textHash + text.charAt(i)) % prime;
    }
    
    // 滑动窗口
    for (int i = 0; i <= n - m; i++) {
        if (patternHash == textHash) {
            // 哈希值相等,检查字符是否真的匹配
            boolean match = true;
            for (int j = 0; j < m; j++) {
                if (text.charAt(i + j) != pattern.charAt(j)) {
                    match = false;
                    break;
                }
            }
            if (match) {
                return i;
            }
        }
        
        // 计算下一个窗口的哈希值
        if (i < n - m) {
            textHash = (256 * (textHash - text.charAt(i) * h) + 
                       text.charAt(i + m)) % prime;
            if (textHash < 0) {
                textHash += prime;
            }
        }
    }
    
    return -1;
}

# 🎯 经典问题

# 最长公共子序列

public int longestCommonSubsequence(String text1, String text2) {
    int m = text1.length();
    int n = text2.length();
    int[][] dp = new int[m + 1][n + 1];
    
    for (int i = 1; i <= m; i++) {
        for (int j = 1; j <= n; j++) {
            if (text1.charAt(i - 1) == text2.charAt(j - 1)) {
                dp[i][j] = dp[i - 1][j - 1] + 1;
            } else {
                dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
            }
        }
    }
    
    return dp[m][n];
}

# 最长回文子串

public String longestPalindrome(String s) {
    if (s == null || s.length() < 2) {
        return s;
    }
    
    int start = 0, maxLen = 1;
    
    for (int i = 0; i < s.length(); i++) {
        // 奇数长度回文
        int len1 = expandAroundCenter(s, i, i);
        // 偶数长度回文
        int len2 = expandAroundCenter(s, i, i + 1);
        
        int len = Math.max(len1, len2);
        if (len > maxLen) {
            maxLen = len;
            start = i - (len - 1) / 2;
        }
    }
    
    return s.substring(start, start + maxLen);
}

private int expandAroundCenter(String s, int left, int right) {
    while (left >= 0 && right < s.length() && 
           s.charAt(left) == s.charAt(right)) {
        left--;
        right++;
    }
    return right - left - 1;
}

# 🔍 练习题目

# 基础操作

# 字符串匹配

# 高级问题