数据结构升华部分:排序与字符串匹配算法应用

数据结构入门学习(全是干货)——综合应用

习题选讲 - 排序与字符串匹配算法

习题选讲 - Insert or Merge

习题-IOM.1 插入排序的判断

题意理解

如何区分简单插入和非递归的归并排序

  1. 插入排序:前面有序,后面没有变化。
  2. 归并排序:分段有序。

捏软柿子算法

  • 在插入和归并两种算法里,判断插入排序较容易。

判断是否为插入排序

  1. 从左向右扫描,直到发现顺序不对,跳出循环。
  2. 从跳出地点继续向右扫描,与原始序列比对,若发现不同,则判断为“非插入排序”。如果在对比过程中发现不同,跳出循环。
  3. 循环自然结束,则判断为“是”,返回跳出地点。

解析:可以返回一个布尔值,例如非为0、是为1,但如果返回“是”,插入排序需继续进行,从左向右扫描找到执行下一步的地点。因此返回“是”的同时返回跳出地点。

如果是插入排序,则从跳出地点开始进行一趟插入。

习题-IOM.2 归并段的判断

判断归并段的长度

错误的想法:

  1. 从头开始连续有序的子列长度?
  2. 所有连续有序子列的最短长度?
  • 保险的判断方法:从原始序列出发,真正进行归并排序。每归并一趟就将归并的中间结果与当前序列做比对,什么时候每一个数都对上了就继续执行。
for (l=2;l<=N;l*=2)
    //在保证了l是4的情况下,要检查看能不能是8,我们要重复前面的步骤看两段之间的衔接点是不是有序

  • 红色位置没有序了时跳出循环,此时l为4,直接以4为归并段继续执行下一趟的归并。

其他数据测试

最小N(应该多大?)

边界测试是每道题的关键组成部分。

  • N等于1时,序列仅一个数字,排序前后结果相同,因此解不唯一。要求区分两种算法的最小N为4:
    1. 插入排序第一步,无变化。
    2. 归并排序第一步,所有元素变了。

最大N

习题选讲 - Sort with Swap(0,*)

习题-SWS.1 环的分类

题意理解

  • 给定N个数字的排列,如何仅利用与0交换达到排序目的?0扮演空位的角色。

环的分类

习题-SWS.2 算法示例

对于不包含0的交换操作次数为n+1,包含0则是n-1次。

习题选讲 - Hashing - Hard Version

习题-HHV 算法思路概述

这是哈希问题的逆问题

题意理解

  1. 已知H(x) = x%N,利用线性探测解决冲突问题。
  2. 先给出散列映射的结果,反求输入顺序。
    • 当元素x被映射到H(x)位置,发现该位置已被y占用,则y一定在x之前被输入。

限制:为确保解唯一,若几个元素可能同时被插入,则按从小到大顺序插入。

因为12模11,余数为1,所以跟12冲突,放在12下面。后面都是类型的操作

依次输入顺序为

串的模式匹配(KMP算法)

KMP-1. 问题及简单解决方案

什么是串

  1. 线性存储的一组数据(默认是字符)。

  2. 特殊操作集。

    1.求串的长度
    2.比较两串是否相等
    3.两串相接
    4.求子串
    5.插入子串
    6.匹配子串(有难度)
    7.删除子串
    

什么是串的模式匹配

目标:给定一段文本,从中找出某个指定的关键字

例如从一本Thomas Love Peacock写于十九世纪的小说《Headlong Hall》中找到那个最长的单词: osseocarnisanguineoviscericartilaginonervomedullary

或者从古希腊喜剧《Assemblywomen》中找到一道菜的名字: Lopadotemachoselachogaleokranioleipsanodrimhypotrimmatosilphioparaomelitokatakechymenokichlepikossyphophattoperisteralektryonoptekephalliokigklopeleiolagoiosiraiobaphetraganopterygon

模式匹配目标

  • 给定文本,从中找出指定的关键字。

Position PatterMatch(char *string,char *pattern)//position指位置
    //模式匹配就是给定一段文本(string),给定一个模式(*pattern),我们要通过PatterMatch函数来返回这个pattern里string第一次出现的位置

简单实现

方法1:C语言库函数strstr。

接口:char *strstr(char *string,char *pattern)
    //返回的是char *这个类型的变量(指向某个字符的指针),变量里面存的是pattern这个字符串第一个字母在string出现的时候那个字母所在的位置
    //一个小Demo
#include <stdio.h>
#include <string.h>//库要记得包含进来
    
typedef char* Position;//给char*重新起个名字,让不懂的人也可以知道返回的是一个位置

int main()
{
    char string[] = "This is a simple example.";
    char pattern[] = "simple";
    Position p = strstr(string,pattern);
    if( p == NotFound ) printf("Mot Found.\n");//能不能找到进行一个判断
    else printf("%s\n",p);
    return 0;
}
//输出:simple example.
//如果输入的找不到,就会输出一个空指针(#define NotFound NULL)

  • strstr的最坏时间复杂度为O(nm),当模式较小时可用,但当两者都较大时需谨慎。

简单改进

方法2:从末尾开始比。

时间复杂度:T = O(n)//仅仅是根据上方的例子进行的改动,如果pattern = "aab"换成"baa"一样要芭比Q
    所以这个改进是没啥作用的
KMP-2. KMP 算法思路

大师改进

方法3:KMP算法,时间复杂度为O(n+m)。

  • 简单的往前错一位的比较是完全没有必要的没有意义的,如下图

  • KMP算法的想法:

  • 指针x不回退,继续从x开始比较。

match的具体例子

下标从090个字符对应的是一个长度为1的子串,所以他不可能产生匹配,match就永远是-101:a跟b是配不上的,match也为-1
0-2:a和c配不上,ab和bc也配不上,所以match还是为-1
0-3:ab和ca是配不上的,abc跟bca也配不上,a对应的j为0,所以match也为0
//此时限制条件是最大i是小于j的,如果i=j的话那就相当于自己等于自己就没有意义了(p0...pj = p0...pj)
    //所以我们考虑他的真子串
0-4:a跟b配不上,abc跟cab配不上,ab跟ab能配上,match值为1...
  • 对于pattern = abcabcacab,最后3个字符的match值为-1, 0, 1。

对于 pattern = abcabcacab,最后 3 个字符的 match 值是多少?-1, 0, 1

在早期的教科书上被叫做failure(失败的意思)

match值的含义:

例子:从0到6的子串,首跟尾能配上的小串,从0开始他的尾部下标为3,abca跟abca能配上。这就是match的含义

此代码块内容来自百度百科:
    KMP算法是一种改进的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt提出的,因此人们称它为克努特—莫里斯—普拉特操作(简称KMP算法)。KMP算法的核心是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。具体实现就是通过一个next()函数实现,函数本身包含了模式串的局部匹配信息。KMP算法的时间复杂度O(m+n)
    
    KMP算法是三位学者在 Brute-Force算法的基础上同时提出的模式匹配的改进算法。Brute- Force算法在模式串中有多个字符和主串中的若干个连续字符比较都相等,但最后一个字符比较不相等时,主串的比较位置需要回退。KMP算法在上述情况下,主串位置不需要回退,从而可以大大提高效率

模式匹配类型

(1)精确匹配
如果在目标T中至少一处存在模式P,则称匹配成功,否则即使目标与模式只有一个字符不同也不能称为匹配成功,即匹配失败。给定一个字符或符号组成的字符串目标对象T和一个字符串模式P,模式匹配的目的是在目标T中搜索与模式P完全相同的子串,返回T和P匹配的第一个字符串的首字母位置  。
(2)近似匹配
如果模式P与目标T(或其子串)存在某种程度的相似,则认为匹配成功。常用的衡量字符串相似度的方法是根据一个串转换成另一个串所需的基本操作数目来确定。基本操作由字符串的插入、删除和替换来组成
KMP-3. KMP 算法实现
    KMP算法是一种改进的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt提出的,因此人们称它为克努特—莫里斯—普拉特操作(简称KMP算法)。KMP算法的核心是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。具体实现就是通过一个next()函数实现,函数本身包含了模式串的局部匹配信息。KMP算法的时间复杂度O(m+n)
    
    KMP算法是三位学者在 Brute-Force算法的基础上同时提出的模式匹配的改进算法。Brute- Force算法在模式串中有多个字符和主串中的若干个连续字符比较都相等,但最后一个字符比较不相等时,主串的比较位置需要回退。KMP算法在上述情况下,主串位置不需要回退,从而可以大大提高效率
  • KMP算法实现示意。

一直走到指针不匹配

Position KMP(char *string,char *pattern )
{
    int n = strlen(string);//strlen得到string的长度,下方也是一样 复杂度:O(n)
    int m = strlen(pattern);//复杂度:O(m)
    int s,p,*match;//声明两个指针
    if(n < m) return NotFound;//找的n不可能比m短 
    match = (int *)malloc(sizeof(int) *m);
    BuildMatch(pattern,match);//Tm = O(?)
    s = p =0;
    while( s<n &&p<m){  //当这两个指针一起往前飞,任何一个指针先指到自己指的串的末尾的时候结束,复杂度O(n)
    	if(string[s] == pattern[p]){ s++;p++; }//p有时候加加有时候回退,但s永远加加
    	else if (p>0) p = match[p-1]+1;//为了防止得到段错误,这里加上条件p>0
    //如果p = 0的话,意味着pattern从第一个字符就不匹配,这个时候p不动,s向前走一格
    	else s++;//当string[s] == pattern[p]不匹配,我们s++,继续下一轮匹配
	}
    //在我们跳出while循环的时候,p指针已经碰到pattern的末尾(p==m),那就是完全的匹配上了
    //反之p还没有到结尾,而string已经到p的结尾了,就意味着我们找不到这个模式
    return (p == m) ? (s-m) : NotFound; 
}

KMP的整体时间复杂度
  • T = O(n+m+Tm)。
KMP-4. BuildMatch 的实现原理

  • 如果采用这种方法,时间复杂度将达到Tm = O(m³)。

新想法:计算j的match值与j-1的match值的关系。

假如我们这是从0到j-1的字段

  • match[j] = match[j-1] + 1(最多持平)。

如果 match[j-1]+1 这个位置上的字符与 j 位置上的字符相等,match[j] 会有可能比 match[j-1]+1 更大吗?没可能

match[j] = match[j-1] + 1 (最多持平啦,利用反证法证明)

且能得到这个结果的前提是运行很好

当 pattern[match[j-1]+1] != pattern[j] 时,下一个待与 pattern[j] 比较的元素下标是:match[match[j-1]]+1

KMP-5. BuildMatch的编程实现
void BuildMatch(char *pattern, int *match) {
    int i, j;
    int m = strlen(pattern); // 复杂度O(m)
    match[0] = -1; // 初始化
    for (j = 1; j < m; j++) { // 复杂度O(m)
        i = match[j - 1]; // 获取前一个match值
        while ((i >= 0) && (pattern[i + 1] != pattern[j])) // 检查条件
            i = match[i]; // 回退
        if (pattern[i + 1] == pattern[j])
            match[j] = i + 1; // 更新match值
        else
            match[j] = -1; // 无匹配
    }
}

整个算法复杂度:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/883613.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

react hooks--useCallback

概述 useCallback缓存的是一个函数&#xff0c;主要用于性能优化!!! 基本用法 如何进行性能的优化呢&#xff1f; useCallback会返回一个函数的 memoized&#xff08;记忆的&#xff09; 值&#xff1b;在依赖不变的情况下&#xff0c;多次定义的时候&#xff0c;返回的值是…

【计算机组成原理】实验一:运算器输入锁存器数据写实验

目录 实验要求 实验目的 主要集成电路芯片及其逻辑功能 实验原理 实验内容及步骤 实验内容 思考题 实验要求 利用CP226实验箱上的K16&#xff5e;K23二进制拨动开关作为DBUS数据输入端&#xff0c;其它开关作为控制信号的输入端&#xff0c;将通过K16&#xff5e;K23设定…

Linux:终端(terminal)与终端管理器(agetty)

终端的设备文件 打开/dev目录可以发现其中有许多字符设备文件&#xff0c;例如对于我的RedHat操作系统&#xff0c;拥有tty0到tty59&#xff0c;它们是操作系统提供的终端设备。对于tty1-tty12使用ctrlaltF*可以进行快捷切换&#xff0c;下面的命令可以进行通用切换。 sudo ch…

【Linux】项目自动化构建工具-make/Makefile 详解

&#x1f525; 个人主页&#xff1a;大耳朵土土垚 &#x1f525; 所属专栏&#xff1a;Linux系统编程 这里将会不定期更新有关Linux的内容&#xff0c;欢迎大家点赞&#xff0c;收藏&#xff0c;评论&#x1f973;&#x1f973;&#x1f389;&#x1f389;&#x1f389; 文章目…

Studying-图论包含的算法总结

目录 1.DFS&#xff08;深度优先搜索&#xff09; 代码框架&#xff1a; 2. BFS&#xff08;广度优先搜索&#xff09; 代码框架&#xff1a; 3. 并查集 4.最小生成树之Prim 5.最小生成树之Kruskal 6.拓扑排序 7. 最短路径之-dijkstra&#xff08;朴素版&#xff…

[附源码]在线音乐系统+SpringBoot+Vue前后端分离

今天带来一款优秀的项目&#xff1a;在线音乐系统源码 。 系统采用的流行的前后端分离结构&#xff0c;内含功能包括 "管理后台"&#xff0c;“用户端”&#xff0c;“评论系统”&#xff0c;“歌手&#xff0c;歌曲管理”&#xff0c;“用户系统”,"统计"…

c++继承详解

从这篇文章开始&#xff0c;我们正式进入c进阶篇章 继承的概念及定义 概念 继承(inheritance)机制是⾯向对象程序设计使代码可以复⽤的最重要的⼿段&#xff0c;它允许我们在保持原有 类特性的基础上进⾏扩展 通俗来讲就是&#xff1a;父亲的遗产传给自己的子女&#xff0c;…

Autosar学习----AUTOSAR_SWS_BSWGeneral(七)

&#x1f4a5;&#x1f4a5;&#x1f50d; &#x1f50d; 欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f421;优势&#xff1a;❤️博客内容尽量做到通俗易懂&#xff0c;逻辑清晰。 ⛳️座右铭&#xff1a;恒心&#xff0c;耐心&#xff0c;静心。 ⛳️ 欢迎一起…

力扣958:判断二叉树是否为完全二叉树

给你一棵二叉树的根节点 root &#xff0c;请你判断这棵树是否是一棵 完全二叉树 。 在一棵 完全二叉树 中&#xff0c;除了最后一层外&#xff0c;所有层都被完全填满&#xff0c;并且最后一层中的所有节点都尽可能靠左。最后一层&#xff08;第 h 层&#xff09;中可以包含 …

828华为云征文|Flexus云服务器X实例实践:安装SimpleMindMap思维导图工具

828华为云征文&#xff5c;Flexus云服务器X实例实践&#xff1a;安装Ward服务器监控工具 引言一、Flexus云服务器X实例介绍1.1 Flexus云服务器X实例简介1.2 主要使用场景 二、购买Flexus云服务器X实例2.1 购买规格参考2.2 查看Flexus云服务器X实例状态 三、远程连接Flexus云服务…

AIGAME的核心技术竞争力与未来生态规划

AIGAME凭借其领先的区块链和人工智能技术&#xff0c;打造了全球首个融合链游、DeFi和加密聊天的Web3娱乐平台。平台的核心技术创新和多元化生态规划&#xff0c;将推动全球虚拟资产管理和娱乐行业的变革。 AIGAME的核心技术竞争力源于其对区块链和人工智能&#xff08;AI&…

衡石分析平台系统管理手册-功能配置之SMTP 服务

SMTP 服务​ SMTP(Simple Mail Transfer Protocol)即简单邮件传输协议。它是一组用于从源地址到目的地址传输邮件的规范&#xff0c;通过它来控制邮件的中转方式。 HENGSHI 用户需要开启 SMTP 服务并进行配置&#xff0c;才能收到系统发送邮件。 SMTP 服务需要用户配置服务器…

Linux(含麒麟操作系统)如何实现多显示器屏幕采集录制

技术背景 在操作系统领域&#xff0c;很多核心技术掌握在国外企业手中。如果过度依赖国外技术&#xff0c;在国际形势变化、贸易摩擦等情况下&#xff0c;可能面临技术封锁和断供风险。开发国产操作系统可以降低这种风险&#xff0c;确保国家关键信息基础设施的稳定运行。在一…

Java文件上传同时传入JSON参数

前言 此篇文章用于解决一个接口内同时完成文件的上传及JSON参数的传入(生产环境已验证); 1.准备接口 import cn.cdjs.vo.UserVO; import cn.hutool.json.JSONUtil; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFi…

虚拟社交的新时代:探索Facebook的元宇宙愿景

随着技术的不断进步&#xff0c;社交媒体的形态也在悄然变化。Facebook&#xff08;现名Meta&#xff09;正站在这一变革的前沿&#xff0c;积极探索元宇宙的愿景。元宇宙不仅是虚拟现实&#xff08;VR&#xff09;和增强现实&#xff08;AR&#xff09;的结合&#xff0c;更是…

Qt_对话框QDialog的介绍

目录 1、新建项目对话框 2、非模态对话框 3、模态对话框 4、自定义对话框 5、Qt内置对话框 5.1 消息对话框QMessageBox 5.2 颜色对话框QColorDialog 5.3 文件对话框QFileDialog 5.4 字体对话框QFontDialog 5.5 输入对话框QInputDialog 结语 前言: 在Qt中&…

【数据结构】排序算法---桶排序

文章目录 1. 定义2. 算法步骤3. 演示3.1 动态演示13.2 动态演示23.3 图片演示13.4 图片演示2 4. 性质5. 算法分析6. 代码实现C语言PythonJavaCGo 结语 1. 定义 桶排序&#xff08;英文&#xff1a;Bucket sort&#xff09;是计数排序的升级版&#xff0c;适用于待排序数据值域…

C# 利用simd比较两个文件是否相等(高性能)

主要用到两个指令集&#xff0c;CompareEqual指令与MoveMask指令&#xff0c;因为电脑cpu原因&#xff0c;我们采用Avx2。 Avx2.CompareEqual&#xff0c;比较两个Vector256<byte>向量&#xff0c;如果元素相同返回255&#xff0c;否则返回0。 Avx2.MoveMask如果Vector…

【初阶数据结构】详解二叉树 - 树和二叉树(三)(递归的魅力时刻)

文章目录 前言1. 二叉树链式结构的意义2. 手搓一棵二叉树3. 二叉树的遍历&#xff08;重要&#xff09;3.1 遍历的规则3.2 先序遍历3.3 中序遍历3.4 后序遍历3.5 遍历的代码实现3.5.1 先序遍历代码实现3.5.2 中序遍历代码实现3.5.3 后序遍历代码实现 4. 统计二叉树结点的个数5.…

2024年9月26日--- Spring-AOP

SpringAOP 在学习编程过程中&#xff0c;我们对于公共方法的处理应该是这样的一个过程&#xff0c;初期阶段如下 f1(){Date now new Date();System.out.println("功能执行之前的各种前置工作"now)//...功能代码//...功能代码System.out.println("功能执行之前…