• HDU-1711-Number Sequence(KMP)(Rabin-Karp)


    • Rabin-Karp
      Accepted 1711 904MS 5272K 1310 B G++
      #include "bits/stdc++.h"
      using namespace std;
      typedef long long LL;
      const int MAXN = 1e6 + 5; 
      const int SEED = 1e9 + 7;
      int arr[MAXN];
      int main() {
          int t, n, m, k;
          scanf("%d", &t);
          while (t--) { 
              LL p = 0, s = 0, head = 1;
              bool flag = false;
              scanf("%d%d", &n, &m);
              for (int i = 1; i <= n; i++) {
                  scanf("%d", &arr[i]);
              }
              // 获取模式串(M数组)的哈希值 
              for (int i = 1; i <= m; i++) {
                  scanf("%d", &k); 
                  head *= SEED;
                  p = p * SEED + k;
              }
              // 获取arr[0]所表示的长度为m的串的哈希值 
              for (int i = 1; i < m; i++) {
                  /*
                  比较标准的写法是s = (s * SEED + arr[i]) % MOD;(MOD是一个和SEED互质的数)
                  这里利用LL的溢出来省略MOD,可以将MOD看成2的64次方 
                  */
                  s = s * SEED + arr[i];
              } 
              for (int i = 1; i <= n - m + 1; i++) {
                  // 用arr[i - 1]所表示的长度为m的串的哈希值得到arr[i]所表示的长度为m的串的哈希值  
                  s = s * SEED - head * arr[i - 1] + arr[i + m - 1];
                  if (s == p) {
                      flag = true;
                      printf("%d
      ", i);
                      break;
                  }
              }
              if (!flag) {
                  puts("-1");
              }
          }
          return 0;
      } 

      Rabin-Karp获取哈希值的形式有点像进制转换,由于计算机内二进制加减是不管符号的所以p和s变成负数也无所谓,用unsigned long long和long long是一样的。但是Rabin-Karp不保证匹配结果绝对正确,因为不同的串哈希值可能一样(long long的范围只有2的64次方,但是本题数组值的范围是[-1000000, 1000000],只要三四位产生的串的数量long long就不够放了)所以如果竞赛中用此法错了,可以尝试改SEED。还不行那就只能换方法了。

    • KMP
      Accepted 1711 842MS 5360K 802 B G++
      #include "bits/stdc++.h"
      using namespace std;
      const int MAXN = 1e6 + 5;
      const int MAXM = 1e4 + 5; 
      int s[MAXN], p[MAXM], Next[MAXM] = {-1};
      int t, n, m;
      int kmp() {
          int i = 0, j = -1;
          // 求模式串的Next 
          while (i < m) {
              if (j == -1 || p[i] == p[j]) {
                  Next[++i] = ++j;
              } else {
                  j = Next[j];
              }
          }
          i = 0, j = 0;
          while (i < n) {
              if (j == -1 || s[i] == p[j]) {
                  i++;
                  if (++j == m) {
                      // 由于题目题目描述的数组下标从1开始,所以追加1 
                      return i - m + 1;
                  }
              } else {
                  j = Next[j];
              }
          }
          return -1;
      }
      int main() {
          scanf("%d", &t);
          while (t--) {
              scanf("%d%d", &n, &m);
              for (int i = 0; i < n; i++) {
                  scanf("%d", &s[i]);
              }
              for (int i = 0; i < m; i++) {
                  scanf("%d", &p[i]);
              }
              printf("%d
      ", kmp());
          }
          return 0;
      } 

      复杂度为O(M + N)

  • 相关阅读:
    SQL语句 分页实现
    PHPexcel入门教程
    json_decode返回null,使用echo json_last_error(); 返回4
    配置mysql可局域网内访问
    thinkphp5.0安装composer安装topthink/think-captcha
    linux下mysql忘记密码怎么办
    centos7 设置mysql账号密码开放3306端口实现远程登陆
    高级数据结构第七章A . 数列(树状数组逆序对)
    高级数据结构第六章E . 苹果树 (dfs+树状数组)
    高级数据结构第六章C . 奶牛狂欢节(两个树状数组)
  • 原文地址:https://www.cnblogs.com/Angel-Demon/p/10309508.html
Copyright © 2020-2023  润新知