AcWing 算法基础课二 数据结构 链表 栈 队列 并查集 哈希表

单链表.

AcWing 算法基础课二 数据结构 链表 栈 队列 并查集 哈希表_第1张图片

AcWing. 826.单链表

import java.util.Scanner;
public class Main{
        static int[] e = new int[100010];//结点i的值
        static int[] ne = new int[100010];//结点i的next指针
        static int idx,head;//head是头结点,idx存当前已经用到了哪个点
        public static void init(){
            idx = 0;
            head = -1;
        }
    //H向链表头插入一个数x;
    public static void add_head(int x){
        e[idx] = x;
        ne[idx] = head;
        head = idx++;
    } 
    //I在第k位数后面插入一个数x
    public static void add(int k,int x){
        e[idx] = x;
        ne[idx] = ne[k];
        ne[k] = idx++;
    }
    //D删除第k个数后面得数
    public static void remove(int k){
        ne[k] = ne[ne[k]];
    }
    public static void main(String[] args){
         Scanner scan = new Scanner(System.in);
        int m = scan.nextInt();

        init();
        while(m -- > 0){
            //因为java中没有输入一个字符,所以用字符串转字符
            String s = scan.next();
            char op = s.charAt(0);

            if(op == 'H'){
                int x = scan.nextInt();
                add_head(x);
            }else if(op == 'D'){
                int k = scan.nextInt();
                if(k == 0) head = ne[head];
                else remove(k-1);
            }else {
                int k = scan.nextInt();
                int x = scan.nextInt();
                add(k-1,x);
            }
        }
        for(int i = head;i != -1;i = ne[i] ){
            System.out.print(e[i] +  " ");
        }
    }
}

双链表

AcWing 827.双链表

import java.util.Scanner;
public class Main{
    static int N = 100010;
    static int[] e = new int[N];//元素
    static int[] r = new int[N];//右指针
    static int[] l = new int[N];//左指针
    static int idx;

    //删除第k位插入的数
    public static void remove(int k){
        r[l[k]] = r[k];
        l[r[k]] = l[k];
    }
    //这是在第k位数后面插入一个数x
    public static void add_all(int k,int x){
        e[idx] = x;
        r[idx] = r[k];
        l[idx] = k;
        l[r[k]] = idx;
        r[k] = idx++;
    }
    public static void main(String[] args){
        Scanner scan = new Scanner(System.in);
        int m = scan.nextInt();

        r[0] = 1;l[1] = 0;idx = 2;

        while(m -- > 0){
            String s = scan.next();
            char op = s.charAt(0);
            if(op == 'L'){
                int x = scan.nextInt();
                add_all(0,x);
            }else if(op == 'R'){
                int x = scan.nextInt();
                add_all(l[1],x);
            }else if(op == 'D'){
                int k = scan.nextInt();
                remove(k + 1);
            }else if(s.equals("IR")){
                int k  = scan.nextInt();
                int x = scan.nextInt();
                add_all(k + 1,x);
            }else {
                int k = scan.nextInt();
                int x = scan.nextInt();
                add_all(l[k+1],x);
            }
        }
       for(int i = r[0];i != 1; i= r[i]){
            System.out.print(e[i]  + " ");
        }
    }
}

AcWing 算法基础课二 数据结构 链表 栈 队列 并查集 哈希表_第2张图片

AcWing 828.模拟栈

import java.util.Scanner;
public class Main{
    public static void main(String[] args){
        Scanner scan = new Scanner(System.in);
        int m = scan.nextInt();
        int[] stl = new int[100010];
        int tt = 0;

        while(m -- > 0){
            String s = scan.next();

            if(s.equals("push")){
                int x= scan.nextInt();
                stl[++tt] = x;
            }else if(s.equals("pop")){
                tt--;
            }else if(s.equals("empty")){
                if(tt > 0){
                    System.out.println("NO");
                }else System.out.println("YES");
            }else{
                System.out.println(stl[tt]);
            }

        }
    }
}

AcWing 3302.表达式求值

import java.util.*;
public class Main{
    public static void main(String[] args){
        Scanner scan = new Scanner(System.in);
        //以字符串形式输入表达式
        String s = scan.next();
        //map来添加运算符号进去,定义优先级
        Map map = new HashMap<>();
        map.put('+',1);
        map.put('-',1);
        map.put('*',2);
        map.put('/',2);

        Stack op = new Stack<>();//存运算符号
        Stack num = new Stack<>();//存数字

        for(int i = 0 ; i < s.length(); i ++ ){
            char c = s.charAt(i);
            //判断c字符是不是数字
            if(Character.isDigit(c)){
                int x = 0,j = i;
                //数字可能会是多位数,
                while(j < s.length() && Character.isDigit(s.charAt(j))){
                    x = x * 10 + s.charAt(j) - '0';
                    j++;
                }
                num.push(x);//将数字x存入数字栈栈顶
                i = j - 1;//重新赋值i
            }else if(c == '('){
                op.push(c); // 将左括号存入字符栈栈顶
            }else if(c == ')'){
                //如果栈顶不等于左括号,一直计算下去;
                while(op.peek() != '('){
                    eval(op,num);
                }
                op.pop(); // 将左括号弹出栈顶
            }else { //如果是正常字符
                while(!op.empty() && op.peek() != '(' && map.get(op.peek()) >= map.get(c)){
                    eval(op,num);
                }
                op.push(c);
            }
        }
        while(!op.empty()) eval(op,num);
        System.out.println(num.peek());
    }
    public static void eval(Stack op,Stack num){
        int b = num.pop();
        int a = num.pop();

        char c = op.pop();
        if(c == '+'){
           num.push(a+b);
        }else if(c == '-'){
            num.push(a-b);
        }else if(c == '*'){
            num.push(a*b);
        }else {
            num.push(a/b);
        }
    }
}

队列

AcWing 算法基础课二 数据结构 链表 栈 队列 并查集 哈希表_第3张图片

AcWing 829. 模拟队列

import java.util.Scanner;
public class Main{
    public static void main(String[] args){
        Scanner scan = new Scanner(System.in);
        int m = scan.nextInt();
        //队列是在tt队尾插入元素,队头hh弹出元素
        int[] dl = new int[100010];
        int hh = 0;
        int tt = -1;
        while(m -- > 0){
            String s = scan.next();
            if(s.equals("push")){
                int x = scan.nextInt();
                dl[++tt] =  x;
            }else if(s.equals("pop")){
                hh++;
            }else if(s.equals("empty")){
                if(hh <= tt) System.out.println("NO");
                else System.out.println("YES");
            }else {
                System.out.println(dl[hh]);
            }
        }
    }
}

单调栈

AcWing 830.单调栈

import java.util.*;
public class Main{
    public static void main(String[] args){
        Scanner scan = new Scanner(System.in);
        int n = scan.nextInt();
        int[] stk  = new int[100010];
        int tt = 0;

        for(int i = 0 ; i < n ;  i++ ){
            int x = scan.nextInt();
            //如果栈非空 ,栈顶元素>= x,那么说明栈顶这个数不满足需求,
            //因为比较的是左边第一个最近最小的数,所以就把stk[tt]弹出了;
            while(tt!=0 && stk[tt] >= x){
                tt--;
            }
            //如果弹出操作完了之后,栈不是空的,就输出栈顶元素,
            if(tt != 0) System.out.print(stk[tt]+" ");
            //否则就是栈是空的,输出-1
            else System.out.print("-1" + " ");
            //最后将x插入栈顶;
            stk[++tt] = x;
        }
    }
}

单调队列

AcWing 154.滑动窗口

import java.io.*;
public class Main{
    static int N = 1000010;
    static int n,k;//数组长度 和 滑动窗口长度
    static int hh,tt;//队头队尾
    static int[] q = new int[N];//q是队列 存的是 下标
    static int[] a = new int[N];
    public static void main(String[] args)throws IOException{
        BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
        PrintWriter wt = new PrintWriter(new OutputStreamWriter(System.out));
        String[] st = bf.readLine().split(" ");
        n = Integer.parseInt(st[0]);
        k = Integer.parseInt(st[1]);
        String[] str = bf.readLine().split(" ");
        for(int i = 0 ; i < n ; i ++ ) a[i] = Integer.parseInt(str[i]);

        hh = 0;tt = - 1;//队头队尾 感觉像双指针
        for(int i = 0 ; i < n ; i ++ ){//i是 滑动窗口的 终点
            //队列非空 hh <= tt且 队头在起点之前 就出栈
            if(hh <= tt && q[hh] < i - k + 1) hh ++;//起点:i-k+1
            //这个while 就是 控制 这个队列的单调性递增!
            //非空 & 队尾元素 >= 新加进来的元素,就将队尾删掉,因 队头存的是窗口中最小的
            while(hh <= tt && a[q[tt]] >= a[i]) tt --;  //求最小值所以保留最小值
            q[++ tt] = i;//当前 位置插到 队尾
            //不足k 不用判断 
            if(i >= k - 1) wt.print(a[q[hh]] + " ");
        }
        wt.println();
        hh = 0;tt = -1;
        for(int i = 0 ; i < n ; i ++){
            if(hh <= tt && q[hh] < i - k + 1) hh ++;
            while(hh <= tt && a[q[tt]] <= a[i]) tt --;//求最大值所以保留最大值

            q[++ tt] = i;
            if(i >= k - 1) wt.print(a[q[hh]] + " ");
        }
        wt.flush();//记得刷新流
    }
}

KMP

AcWing 算法基础课二 数据结构 链表 栈 队列 并查集 哈希表_第4张图片

AcWing 算法基础课二 数据结构 链表 栈 队列 并查集 哈希表_第5张图片

AcWing 831. KMP字符串

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.Scanner;
public class Main{
    static int N = 100010;
    static int ne[] = new int[N];//kmp核心数组next[];
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
        Integer n = Integer.parseInt(br.readLine());//输入p字符的长度
        String s1 = " " + br.readLine();//输入p字符串
        Integer m = Integer.parseInt(br.readLine());
        String s2 = " " + br.readLine();
        char[] a1 = s1.toCharArray();//创建p数组 存字符
        char[] a2 = s2.toCharArray();
        /**
         * ne[]:存储一个字符串以每个位置为结尾的‘可匹配最长前后缀’的长度。
         * next[i]=j 等价 p[1,j]=p[i-j+1,i]
         * 构建ne[]数组:
         *              1,初始化ne[1] = 0,i从2开始。当第一个数时就是0所以不用参与。默认是0;
         *              2,若匹配,s[i]=s[j+1]说明1~j+1是i的可匹配最长后缀,ne[i] = ++j;
         *              3,若不匹配,则从j的最长前缀位置+1的位置继续与i比较
         *              (因为i-1和j拥有相同的最长前后缀,我们拿j的前缀去对齐i-1的后缀),
         *              即令j = ne[j],继续比较j+1与i,若匹配转->>2
         *              4,若一直得不到匹配j最终会降到0,也就是i的‘可匹配最长前后缀’的长度
         *              要从零开始重新计算
         */
        for(int i = 2,j = 0;i <= n ;i++) {
            //这里判断从j是不是>=0,如果< 0,表示还没有前缀和后缀相等
            while(j!=0&&a1[i]!=a1[j+1]) j = ne[j]; //不相等就让j等于上一个数的next[];
            if(a1[i]==a1[j+1]) j++;//匹配 有一个相等,前缀和后缀相等长度为1.
            ne[i] = j;
        }
        /**
         * 匹配两个字符串:
         *      1,从i=1的位置开始逐个匹配,利用ne[]数组减少比较次数
         *      2,若i与j+1的位置不匹配(已知1~j匹配i-j~i-1),
         *      j跳回ne[j]继续比较(因为1~j匹配i-j~i-1,所以1~ne[j]也能匹配到i-ne[j]~i-1)
         *      3,若匹配则j++,直到j==n能确定匹配成功
         *      4,成功后依然j = ne[j],就是把这次成功当成失败,继续匹配下一个位置
         */
        for(int i = 1,j = 0; i <= m;i++) {
            while(j!=0&&a2[i]!=a1[j+1]) j = ne[j];
            if(a2[i]==a1[j+1]) j++;
            if(j==n) {//相等的数= 短的数组的长度,就说明该输出了
                j = ne[j];//输出之后,要继续往下面遍历对比,所以让j=上一个数的缀长度,
                bw.write(i-n+" ");
            }
        }
        /**
         * 时间复杂度:
         *      因为:j最多加m次,再加之前j每次都会减少且最少减一,j>0
         *      所以:while循环最多执行m次,若大于m次,j<0矛盾
         *      最终答案:O(2m)
         */
        //所有write下的内容,会先存在writers中,当启用flush以后,会输出存在其中的内容。
        //如果没有调用flush,则不会将writer中的内容进行输出。
        bw.flush();
    }
}

Trie:高效地存储和查找字符串集合的数据结构

AcWing 算法基础课二 数据结构 链表 栈 队列 并查集 哈希表_第6张图片

AcWing 835. Trie字符串统计

import java.util.Scanner;
public class Main{
    static int N = 100010,idx = 0;//idx是当前用到的下标
    static int[][] song = new int[N][26];//每个点的儿子集合最多26个字母儿子
    static int[] cnt  = new int[N];//存当前结尾的单词有多少个
    static char[] str = new char[N];
    //插入字符串
    public static  void insert(char[] str){
        int p = 0; //下标0表示头结点,根节点
        for(int i = 0 ; i < str.length; i ++ ){
            // 将字符串每个字符a-z 映射成数字;0-25
            int u = str[i] - 'a'; 
            //如果这个儿子分支没有字符,说明这条分支还没有这个字符插入过
            //就创建出来 把【idx】下标赋值上去,作为每个分支的专属坐标
            if(song[p][u] == 0) song[p][u] = ++idx;
            //然后将p往下前进一层
            p = song[p][u];
        }
        //最后停在那一层的那个数字就做标记,说明这是要找的字符串的结尾
        cnt[p]++;
    }
    public static int query(char[] str){
        int p = 0;//从根节点开始,下标是0表示根节点,头结点
        for(int i = 0 ; i < str.length; i ++){
            int u = str[i] - 'a'; // 将字符串每个字符都转化成数字0-25
            //如果这个点上没有标记,就说明没有存入过这个字符,所以返回0
            if(song[p][u] == 0) return 0;
            //如果这个点上面能寻找到这个字符,就让他往下一层继续寻找;
            p = song[p][u];
        }
        //最后查找完之后输出最后一个做标记的点为下标的cnt数组的值。
        return cnt[p];
    }
    public static void main(String[] args){
        Scanner scan = new Scanner(System.in);
        int n = scan.nextInt();
        String sss = scan.nextLine();
        while(n -- > 0){
            String s = scan.nextLine();
            String[] st = s.split(" ");
            String s1 = st[0];
            String s2 = st[1];
            if(s1.equals("I")){
                insert(s2.toCharArray());
            }else{
                System.out.println(query(s2.toCharArray()));
            }
        }
    }
}

AcWing 143. 最大异或对

import java.io.*;
public class Main{
    static int N = 3100010,idx = 0;
    static int[][] song = new int[N][2];
    //插入
    public static void add(int x){
        int p = 0;//从头结点开始
        for(int i = 30 ; i >= 0 ; i -- ){ //从第31位开始遍历
            int u = x >> i & 1;//取出第i位的二进制数
            //判断这一层是空的,就创建,然后赋值下标
            if(song[p][u] == 0) song[p][u] = ++idx;
            //我觉得这个idx不是代表1或0,二维数组的u才代表这一条路的节点数字
            p = song[p][u];//然后让往下前进一层
        }
    }
    //查询
    public static int query(int x){
        int p = 0,res = 0;//从根节点0开始;res存的是这条路径表示的数
        for(int i = 30; i>= 0 ; i --){
            int u = x >> i & 1; //取出第i位的二进制数
//如果该节点的u是0,则判断一下在这一层有没有跟他相反的0,这样方便找最大异或值
            if(song[p][1-u] != 0){ 
                res += (1 << i);//res就将该二进制位对应异或之后的最优解1每一位顺次加起来。因为是异或相反数就是1,这是最优解
                p = song[p][1-u];//然后往最优解那边前进一层。
            }else{//否则就没有 最优解的0匹配1,1匹配0,所以就异或之后的值是0
                //res += (0 << i);因为是0所以可以省略,
                p = song[p][u];//然后让他往不优解那边前进一层。
            }
        }
        return res;//最后返回异或之后的最大值res
    }
    public static void main(String[] args)throws IOException{
        BufferedReader re = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter wt = new BufferedWriter(new OutputStreamWriter(System.out));
        int n = Integer.parseInt(re.readLine());
        String[] s = re.readLine().split(" ");
        for(int i = 0 ; i < n ; i ++ ){
            add(Integer.parseInt(s[i]));
        }
        int res  = 0;
        for(int i = 0 ; i < n ; i ++ ){
            //因为输入的是字符串所以需要转成整形。然后每一次比较res的值谁大,然后将最大值重新赋值给res
            res = Math.max(res,query(Integer.parseInt(s[i])));
        }
        wt.write(res +" ");//最后输出res,因为快输出输出的是字符串,所以需要在后面加上“ ”;
        wt.close();
    }
}

并查集

AcWing 算法基础课二 数据结构 链表 栈 队列 并查集 哈希表_第7张图片

AcWing 836.合并集合

AcWing 算法基础课二 数据结构 链表 栈 队列 并查集 哈希表_第8张图片

AcWing 算法基础课二 数据结构 链表 栈 队列 并查集 哈希表_第9张图片

import java.io.*;

public class Main {
    private static int[] p = new int[(int) 10e5];

    private static int find(int x) {
        if (p[x] != x) p[x] = find(p[x]);
        return p[x];
    }

    public static void main(String[] args) throws IOException {
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(System.out));
        String[] s = reader.readLine().split(" ");
        int n = Integer.parseInt(s[0]), m = Integer.parseInt(s[1]);
        for (int i = 0; i < n; i++) {
            p[i] = i;
        }
        while (m-- > 0) {
            s = reader.readLine().split(" ");
            if ("Q".equals(s[0])) {
                int x = Integer.parseInt(s[1]);
                int y = Integer.parseInt(s[2]);
               writer.write(find(x) == find(y) ? "Yes\n" : "No\n");
            } else {
                int x = Integer.parseInt(s[1]);
                int y = Integer.parseInt(s[2]);
                p[find(x)] = find(y);
            }
        }
          writer.flush();
    }
}

AcWing 837. 连通块中点的数量

AcWing 算法基础课二 数据结构 链表 栈 队列 并查集 哈希表_第10张图片

import java.io.*;

public class Main {
    private static int[] p = new int[(int) 10e5];

    private static int find(int x) {
        if (p[x] != x) p[x] = find(p[x]);
        return p[x];
    }

    public static void main(String[] args) throws IOException {
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(System.out));
        String[] s = reader.readLine().split(" ");
        int n = Integer.parseInt(s[0]), m = Integer.parseInt(s[1]);
         int[] size = new int[n];
        for (int i = 0; i < n; i++) {
            p[i] = i;
            size[i]=1;
        }
        while (m-- > 0) {
            s = reader.readLine().split(" ");
            if ("Q1".equals(s[0])) {//是否在同一块内
                int x = Integer.parseInt(s[1]);
                int y = Integer.parseInt(s[2]);
               writer.write(find(x) == find(y) ? "Yes\n" : "No\n");
            } else if ("Q2".equals(s[0])) {//同一块内有多少节点
                int x = Integer.parseInt(s[1]);
               writer.write(size[find(x)]+"\n");
            } 
            else {
                int x = Integer.parseInt(s[1]);
                int y = Integer.parseInt(s[2]);
                if(find(x) == find(y) ) continue;
                size[find(y)]+=size[find(x)];//别加反了
                p[find(x)] = find(y);
            }
        }
          writer.flush();
    }
}

AcWing 240.食物链

AcWing 算法基础课二 数据结构 链表 栈 队列 并查集 哈希表_第11张图片

AcWing 算法基础课二 数据结构 链表 栈 队列 并查集 哈希表_第12张图片

AcWing 838.堆排序

AcWing 算法基础课二 数据结构 链表 栈 队列 并查集 哈希表_第13张图片

import java.io.*;
public class Main{
    static int[] h=new int[100010];
    static int size;
    public static void main(String[] args) throws IOException {
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(System.out));
        String[] s = reader.readLine().split(" ");
        int n = Integer.parseInt(s[0]), m = Integer.parseInt(s[1]);
         s = reader.readLine().split(" ");
        for (int i = 1; i <= n; i++) {
            h[i]=Integer.parseInt(s[i-1]);
        //  writer.write(h[i]+"\n");
        } 
        
        size=n;
        for(int i=n/2;i>0;i--){
           down(i);
        }
         while(m-->0) {
            writer.write(h[1]+" ");
            h[1]=h[size];
            size--;
            down(1);
        } 
        writer.flush();
    }
    public static void down(int u){
        int t=u;
        if(u*2<=size&&h[u*2]

AcWing 839.模拟堆

AcWing 算法基础课二 数据结构 链表 栈 队列 并查集 哈希表_第14张图片

哈希表

AcWing 算法基础课二 数据结构 链表 栈 队列 并查集 哈希表_第15张图片

AcWing 算法基础课二 数据结构 链表 栈 队列 并查集 哈希表_第16张图片

数据范围是1e9,所以需要先% 再加 再%

AcWing 算法基础课二 数据结构 链表 栈 队列 并查集 哈希表_第17张图片

AcWing 840.模拟散列表

拉链法(数组+单链表)

AcWing 算法基础课二 数据结构 链表 栈 队列 并查集 哈希表_第18张图片

import java.io.*;
import java.util.Arrays;
public class Main{
    static int N=100003,idx=0;
    static int[] h=new int[N];
    static int[] e=new int[N];
    static int[] ne=new int[N];

    public static void main(String[] args) throws IOException {
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(System.out));
        String[] s = reader.readLine().split(" ");
        int n = Integer.parseInt(s[0]);
        
        //数组赋初始值
        Arrays.fill(h, -1);
        while(n-->0){
            s = reader.readLine().split(" ");
            int x=Integer.parseInt(s[1]);
            if("I".equals(s[0])) {//插入
                insert(x);
            }else{
                if( find(x) )
                    writer.write("Yes\n");
                else  writer.write("No\n");
            }
        } 
        writer.flush();
        
    }
    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;
    }
}

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

AcWing 算法基础课二 数据结构 链表 栈 队列 并查集 哈希表_第19张图片

AcWing 算法基础课二 数据结构 链表 栈 队列 并查集 哈希表_第20张图片

AcWing 841.字符串哈希 :快速判断两个字符串是否相等

AcWing 算法基础课二 数据结构 链表 栈 队列 并查集 哈希表_第21张图片

AcWing 算法基础课二 数据结构 链表 栈 队列 并查集 哈希表_第22张图片

unsigned long long 是2^64次 代替了%Q,溢出时相当于 自动取模

AcWing 算法基础课二 数据结构 链表 栈 队列 并查集 哈希表_第23张图片

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)=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次方=1
        for(int i = 1 ; i <= n ; i++ ){
            p[i] = p[i-1] * P;//每一个下标对应P的多少次方
            //预处理公式 前缀哈希的值,P进制,中间*P    
            h[i] = h[i-1] * P + s.charAt(i-1);
        }

        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");
        }
    }
}

AcWing 算法基础课二 数据结构 链表 栈 队列 并查集 哈希表_第24张图片

你可能感兴趣的:(Java从入门到起飞,python,java,算法)