算法-哈希表和相关练习-java

哈希表

哈希表存储方式:1.开放寻址法,2.拉链法

运用:把一个很大的空间映射到比较小的范围(110^9->110^5)

模拟散列表

开放寻址法:直接一个数组模拟蹲坑

1.x mod 10^5(最好质数并且离2的n整次幂尽量远) 2.对于冲突,当前位置有数了就对位置+1直到当前没数为止,一般需要开当前范围的两到三倍,然后定义一个0x3f3f3f是大于10^9的一个数(在最大范围外)

代码:

java 复制代码
import java.util.Scanner;
public class Main{
    static int N = 200003,idx;
    static int nulls = 0x3f3f3f3f;//最大的数
    static int[] h = new int[N];
    public static int find(int x){
        int k = (x % N + N) % N;
        while(h[k]!=nulls && h[k] != x){//不为空且没找到就继续找
            k++;
            if(k==N) k=0;//到结尾了从头开始
        }
        return k;
    }
    public static void main(String[] args){
        Scanner scan = new Scanner(System.in);
        int n = scan.nextInt();
        for(int i = 0; i<N;i++)h[i]=0x3f3f3f3f;
        while(n -- > 0){
            String s = scan.next();
            int x = scan.nextInt();
            int k = find(x);
            if(s.equals("I")){     
                h[k]=x;
            }else{
                if(h[k]!=nulls) System.out.println("Yes");
                else System.out.println("No");
            }
        }
    }
}

拉链法:假设映射到1~10^5内,相当于每个数字的位置都是一个链表,有冲突就插入到当前链表最后面这样

java 复制代码
import java.util.Scanner;
public class Main{
   static int N = 100003,idx;
   static int[] h = new int[N];
   static int[] e = new int[N];
   static int[] ne = new int[N];
   public static void insert(int x){
       int k = (x % N + N) % N;//存储下标位置 防止负数
       e[idx] = x;//赋值
       ne[idx] = h[k];//该点指向下一个节点
       h[k] = idx++;//头指向该节点

   }
   public static boolean find(int x){
       int k = (x % N + N) % N;
       for(int i = h[k];i != -1;i = ne[i]){
           if(e[i] == x){
               return true;
           }    
       }
       return false;
   }
   public static void main(String[] args){
       Scanner scan = new Scanner(System.in);
       int n = scan.nextInt();
       idx = 0;
       for(int i = 0; i<N;i++)h[i]=-1;
       while(n -- > 0){
           String x = scan.next();
           if(x.equals("I")){
               int a = scan.nextInt();
               insert(a);
           }else{
               int b = scan.nextInt();
               if(find(b)) System.out.println("Yes");
               else System.out.println("No");
           }
       }
   }
}

字符串哈希

代码

java 复制代码
import java.util.Scanner ;
public class Main{
    //开的是long类型数组,本来是需要进行前缀hash求完之后需要进行模2的64次方来防止相同的冲突,可能超过我们给的数组大小
    static int N = 100010,P = 131;//p是进制数,惊艳值
    static long[] h = new long[N];//这是存放hash前缀值得数组
    static long[] p = new long[N];//这是存放p的n次方的数组
    public static long get(int l,int r){//这里是将运用了一点前缀和公式的方式进行计算
        //求l-r区间的hash值,就要用h[r] - h[l-1],因为两者位数不用需要让h[l-1]向左边移到跟h[r]对齐
        //就比如求1234的3-4区间位,1234 - 12,12左移然后就让12*10^(4-3+1)=12*10^2=1200,然后1234-1200 = 34,这样进行计算出来
        //然后本题是p进制,所以需要将上面公式中的10换成p就行了
        //h[0] = 0
        //h[1] = h[i-1] * P + str[1] = 0*P+a = a
        //h[2] = a * P + b
        //h[3] = (a*P+b)*P+c = a*p[2]+b*P+c
        //h[4] = (a*p[2]+b*P+c)*P+d = a*p[3]+b*p[2]+c*P+d
        //比如abcd求3-4区间位,就是让h[d]-h[b],h[b]位数不用需要向左移对齐h[d],
        //h[2]*P^(4-3+1)=(a*P+b)*P^2 = a*P^3+b*P^2
        //然后就让h[d] - h[b]求出34区间值,(a*p[3]+b*p[2]+c*P+d) - (a*P^3+b*P^2) = c*P+d
        return h[r] - h[l-1]*p[r-l+1];
    }
    public static void main(String[] args){
        Scanner scan = new Scanner(System.in);
        int n = scan.nextInt();
        int m = scan.nextInt();
        String s = scan.next();
        p[0] = 1;//这个是p的0次方的值,需要单独写出来,非常重要
        for(int i = 1 ; i <= n ; i++ ){
            p[i] = p[i-1] * P;//这里对应每一个下标对应对应P的多少次方
            h[i] = h[i-1] * P + s.charAt(i-1);//这里是公式,预处理前缀哈希的值,因为是P进制,所以中间乘的是P
        }

        while(m -- > 0){
            int l1 = scan.nextInt();
            int r1 = scan.nextInt();
            int l2 = scan.nextInt();
            int r2 = scan.nextInt();
            //判断两个区间是不是相同,用get的方法返回值一样说明区间的hash值是一样的
            if(get(l1,r1) == get(l2,r2)) System.out.println("Yes");
            else System.out.println("No");
        }
    }
}
相关推荐
shayudiandian2 小时前
【Java】面向对象编程
java
余衫马2 小时前
聚类算法入门:像魔法一样把数据自动归类
人工智能·算法·机器学习·聚类
CAU界编程小白2 小时前
数据结构系列之快速排序
数据结构·c++·算法
asom222 小时前
互联网大厂Java求职面试实战:Spring Boot到Kubernetes的技术问答
java·spring boot·kubernetes·oauth2·电商·microservices·面试技巧
I_Jln3 小时前
CountDownLatch:让多线程同步如此简单
java
虎子_layor3 小时前
轻量级哈希扰动工具:Hashids,快速上手
java·spring
逻极3 小时前
VS Code之Java 开发完全指南:从环境搭建到实战优化
java·开发语言
卡提西亚3 小时前
一本通网站1130:找第一个只出现一次的字符
数据结构·c++·笔记·算法·一本通
Moe4883 小时前
JDK动态代理和CGLIB动态代理源码解析
java·后端