IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 算法设计与分析 KMP算法 -> 正文阅读

[数据结构与算法]算法设计与分析 KMP算法

概述

  • KMP问题:字符串str1和str2,str1是否包含str2,如果包含返回str2在str1中的开始位置,如何做到时间复杂度为O(n)
  • 常规思路:从str1的头的尾的字符依次作为str2的开头进行测试,时间复杂度为O(N * M),N:为str1的长度,M:为str2的长度
  • KMP方法的比较方式借鉴了常规方法只是在常规方法的基础上进行加速,每一次比较的出发点可以根据上一次比较得到的数据进行优化,减少比较次数,从而在时间复杂度上进行提升

KMP思路

  • 最长前缀与后缀的匹配长度:在不取到前后长度完全相同之前时,前后缀相同能达到的最大长度
    在这里插入图片描述
    如上图:k的下标为3
  • nextArr数组:对str2求对应所有字符的最长前缀与后缀匹配长度,规定:0位置为 -1;1位置为 0
    在这里插入图片描述
  • str1从 i 位置与str2比较,在str1的x位置与str2的y位置发生不匹配现象
    在这里插入图片描述
    常规思路:str1中x位置跳回 i + 1位置,str2中y位置跳回 0 位置,重新开始比较
    在这里插入图片描述
    KMP思路:得到y位置对应nextArr数组的值,找到y匹配度前面相同的一截;将str1停留在x位置(KMP中str1的x位置只会往后走,绝对不会在退到前面重新比较),str2由y位置移动到前面相同位置的后一位,开始比较
    在这里插入图片描述
  • 解析:因为nextArr,str2中有两段相同,在str1的 j 位置开始是与str2中的后缀相同的,所以可以直接将str2从str1 的 i 位置推到 j 位置,又因为前后缀相同直接从str2前缀相同的下一位与str1的 x位置进行比较
    在这里插入图片描述
  • 例:str1 的 e 与 str2 的 w不相等
    在这里插入图片描述
    第一次跳跃:找到str2的w 位置的nextArr数组对应的值,此时str2 的 t 位置与str 1的 e位置开始比较,相当于:将str2移动到str1中第二个框住 a的位置比较,又因为有一部分相同,所以是 t 位置与 e 位置的比较
    在这里插入图片描述
    第二次跳跃:t 与 e 又不相同,找到str2的t位置的nextArr数组对应的值,str2 的s位置与 str1的e位置比较在这里插入图片描述
    第三次跳跃:s 又与 e不同,此时s的nextArr为0,则跳回str2的开头位置与 e 比较,还是不同,将str1到e的下一个位置,重新开始
    在这里插入图片描述

代码实现

  • nextArr数组的求法
    (1)0位置:-1,1位置:0
    (2)x位置是:n,若x位置与前缀的下一个位置相同,则x + 1位置就是:n + 1;若x位置与前缀的下一个位置不同,前缀下一个位置为:m,就跳到前缀的前缀,若相同,则x + 1位置就是:m+ 1,若不同继续先前找前缀……直到找到最前面若x与最前面相同, x + 1位置就是:1,不同就是0
  • 例:
    在这里插入图片描述

x 的nextArr位置为8,确定 x + 1的nextArr位置就是又x的值决定
(1)若 x 为 e,则 ? 为 x 的nextArr + 1,为 9
(2)若 x 不为 e,就跳到 s 与其比较,若相同 ? 是 e 的nextArr + 1为 4
(3)若 x 不为 s,就跳到最前面 a 比较,若相同 ? 是 s 的nextArr + 1为 1
(4)若 x 不为 a,就是 0

求解 next 数组
    public static int[] getNextArray(char[] str) {
        if (str.length == 1){
            return new int[] {-1};
        }
        //默认,0位置是-1,1位置是1
        int[] nextArr = new int[str.length];
        nextArr[0] = -1;
        nextArr[1] = 1;
        int index = 2; //next数组的位置
        int pre = 0; //要比较字符的位置(前缀的下一个)也有前缀长度的含义
        while (index < str.length){
            //时间复杂度为:O(M),M = chs1.length
            if (str[index - 1] == str[pre]){
                //index - 1 与 pre 位置相同
                //nextArr[index] 就是上一个位置加一
                //pre:前缀长度增加
                nextArr[index] = nextArr[index - 1] + 1;
                index++;
                pre++;
            } else if (pre > 0){
                //不相同,跳到上一个前缀进行比较
                pre = nextArr[pre];
            }else {
                //跳到了最前面,也不相同
                nextArr[index] = 0;
                index++;
            }
        }
        return nextArr;
    }
kmp代码
    public static int kmp(String str1, String str2){
        //匹配成功,返回str1中匹配str2成功的位置,否则返回 -1
        if (str1 == null || str2 == null || str1.length() < 1 || str2.length() < 1){
            return -1;
        }
        char[] chs1 = str1.toCharArray();
        char[] chs2 = str2.toCharArray();
        int index1 = 0;
        int index2 = 0;
        int[] next = getNextArray(chs2);
        while (index1 < chs1.length && index2 < chs2.length){
            //时间复杂度为:O(N),N = chs2.length
            //若是因为index2 == chs2.length结束while,说明匹配成功
            //若只是因为index1 == chs1.length结束while,说明整个匹配失败
            if (chs1[index1] == chs2[index2]){
                index1++;
                index2++;
            } else if (index2 == 0){
                //等同与:else if (next[index2] == -1)
                //index2回到0位置,且str1仍不匹配,直接使index1移动
                index1++;
            } else {
                //index2的跳跃,就是对应下标next数组中的值
                index2 = next[index2];
            }
        }
       //判断是否匹配成功
        return index2 == chs2.length ? index1 - index2 : -1;
    }
  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-02-07 13:58:02  更:2022-02-07 13:58:07 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 18:37:26-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码