字符串处理-字符串哈希

115 阅读3分钟

字符串转整数

面试题67. 把字符串转换成整数

image.png

输入: "4193 with words"
输出: 4193
解释: 转换截止于数字 '3' ,因为它的下一个字符不为数字。

输入: "   -42"
输出: -42
解释: 第一个非空白字符为 '-', 它是一个负号。我们尽可能将负号与后面所有连续出现的数字组合起来,最后得到 -42 。

输入: "-91283472332"
输出: -2147483648
解释: 数字 "-91283472332" 超过 32 位有符号整数范围。 因此返回 INT_MIN (−231) 。

模拟 :

  • 1.丢弃无用的空格字符
  • 第一个非空字符为正负号时,与后面尽可能多的连续数字组合形成整数
  • 除了数字 , 其他要被忽略。
class Solution {
    int min = Integer.MIN_VALUE;
    int max = Integer.MAX_VALUE;
    public int strToInt(String str) {
        char[] s = str.toCharArray();
        int idx = 0;
        int n = s.length;
        while (idx < n && s[idx] == ' ') idx ++;

        int sign = 1;
        if (idx < n && (s[idx] == '+' || s[idx] == '-')) {
            if (s[idx] == '-') sign = -1;
            idx ++;
        }

        int val = 0;
        while (idx < n && s[idx] >= '0' && s[idx] <= '9') {
            if (val > (max - (s[idx] - '0')) / 10) {
                if (sign == -1) return min;
                else return max;
            }
            val *= 10;
            val += s[idx] - '0';
            idx ++;
        }
        val *= sign;
        return val;
    }
}

acwing 字符串哈希

题目链接

image.png 字符串哈希 采用的思想是 : 把字符串看作一个 b 进制数(b 取值于字符串长度) , 计算它在十进制下对p取模的值

简单说就是把一个字符串映射成一个数字 例子 就是把一个字符串如”ABC”映射成一个p进制的数字 “ABC” –> p^2+A + p^1+B + p^0+C = 哈希值, 一般p取131或13331 冲突概率极小 那冲突了怎么ban呢 , 取出来 在比较下稳妥。

如何 计算 字串hash 值?

有点类似前缀和的思想 “ABC” –> p^2+A + p^1+B + p^0+C = 哈希值

   // 处理 进制关系。每段的hash 值
       for (int i = 1 ;i <= n ; i ++) {
           // 前缀和 思想
           // 构造 进制 记录每个 ip次方  [1 位1] [2 位 P] [3 位 P²]····
           // P的进制表
           p[i] = p[i - 1] * P;
           hash[i] = hash[i - 1] * P + s.charAt(i - 1); 
       }

如何计算 A 的哈希值? A 在0 位置 ABC 有 3 位 abc - a00 补位乘对应进制。类似于进制减法
计算公式如下: hash[r1] - hash[l1 - 1] * p[r1 - l1 + 1]

代码

import java.util.*;
import java.io.*;

// 字符串哈希
// 简单说就是把一个字符串映射成一个数字
// 具体点,就是把一个字符串如”ABC”映射成一个p进制的数字
// “ABC” –> p^2+A + p^1+B + p^0+C = 哈希值, 一般p取13113331

public class Main {
  static int n;
  static final int P = 131;
  public static void main(String[] args) {
      Scanner sc = new Scanner(new BufferedInputStream(System.in));
      n = sc.nextInt();
      int m = sc.nextInt();
      String s = sc.next();
      int[] p = new int[n + 10];
      int[] hash = new int[ n + 10];
      p[0] = 1;
      // 处理 进制关系。每段的hash 值
      for (int i = 1 ;i <= n ; i ++) {
          // 前缀和 思想
          // 构造 进制 记录每个 i 的p次方  1 位 0 2 位1 ····
          p[i] = p[i - 1] * P;
          hash[i] = hash[i - 1] * P + s.charAt(i - 1); 
      }
      
      while (m -- > 0) {
          int l1 = sc.nextInt();
          int r1 = sc.nextInt();
          int l2 = sc.nextInt();
          int r2 = sc.nextInt();
          // System.out.println( hash[r1] - hash[l1 - 1] * p[r1 - l1 + 1]);
          
          // System.out.println( hash[r2] - hash[l2 - 1] * p[r2 - l2 + 1]);
          
          String out  = hash[r1] - hash[l1 - 1] * p[r1 - l1 + 1] == hash[r2] - hash[l2 - 1] * p[r2 - l2 + 1] ? "Yes" : "No";
          System.out.println(out);
      }
  }
}

28. 找出字符串中第一个匹配项的下标

class Solution {
   static final int P = 131; 
   public int strStr(String haystack, String needle) {
       int n = haystack.length();
       int m = needle.length();
       // 进制表
       int[] p = new int[ n + 1];
       int[] hashA = new int[n + 1];
       p[0] = 1;
       // 求 haystack 字符串 hash 
       // 进制表  n 一定 大于 m 放在n 求了
       for (int i = 1 ; i <= n ; i ++) {
           p[i] = p[i - 1] * P;
           // 
           hashA[i] = hashA[i - 1] * P + haystack.charAt(i - 1);
       }
       int[] hashB = new int[m + 1];
         for (int i = 1 ; i <= m ; i ++) {
           hashB[i] = hashB[i - 1] * P + needle.charAt(i - 1);
       }
       // 枚举比较hash 值
       for (int i = m ; i <= n ; i ++) {
           // hahs 从 1 开始存 最少是1
           if (hash(p,hashA,i - m + 1,i) == hashB[m] && haystack.substring(i - m, i).equals(needle)) return i - m;
       }
       return -1;
   }

   int hash(int[] p , int[] hash , int l , int r ) {
       return hash[r] - hash[l - 1] * p[r - l + 1];
   }
}