DFS回溯剪枝|KMP通过数组记录减少判断子字符串|思路

news2024/9/21 0:42:12

KMP|DFS回溯剪枝

#1、NC149kmp

在这里插入图片描述
初步思路:

两层for循环,一个T的字符开始与
S的字符比较,挨个比较,遇到不同就continue当前T的字符,重复步骤=》效率太低,超时

eg:
T=ABSABABABD
S=ABABD

S!=A时,退回到A与S比较,发现不同;
继续比较A与A,B与B…A与D,不相等了了。
此时,D前面有两个AB,所以指向S的字符索引只往前移动两个字符,退回到AB|(这里)ABD,即第一个AB公共前缀后面的A这里。
继续A与A比较…

KMP的核心思想是:不必退回到开始的地方!比较过的地方就不用重复比较了!
用一个数组去记录应该退回到哪里合适

next[j - 1] 表示在 S[0…j-1] 这个子字符串中,最长的相同前缀和后缀的长度。如果 S[j] 和当前要比较的字符不匹配,这意味着 S[j] 不能作为前缀的一部分,因此需要找到一个更短的前缀,使得 S[0…next[j-1]] 和 S[i…] 能够匹配。
while 循环用于在 next 数组构建过程中,当当前字符 S.charAt(i) 与 S.charAt(j) 不匹配时,回溯找到 j 的下一个有效值。这个值是 S[0…j-1] 的最长相同前缀和后缀的长度。
为什么 while 在 if 前面:

当 S.charAt(j) != S.charAt(i) 时,说明当前 j 所对应的前缀无法与 i 位置的字符匹配。此时,需要减小 j 的值,直到找到一个匹配的前缀或者 j 减到 0。

while 循环确保即使在多次不匹配的情况下,j 也能正确地回溯到一个有效的值。如果使用 if 语句,那么在 j > 0 且 S.charAt(j) != S.charAt(i) 时,j 只会减少 1,这可能不会找到正确的前缀匹配。

if 条件的作用:当 S.charAt(j) == S.charAt(i) 时,说明当前字符匹配,j 可以安全地向前移动一位,因为 S[0…j] 和 S[i…](从 i 开始的剩余字符串)有一个共同的字符可以匹配。

next[i] = j; 的意义:
无论 S.charAt(j) 和 S.charAt(i) 是否匹配,next[i] 都被设置为 j 的当前值。
如果字符匹配,j 已经增加了 1,next[i] 反映了这个增加;
如果字符不匹配,j 通过 while 循环回溯到了正确的值,next[i] 反映了这个回溯。

 public int[] getNext(String S) {
        int l = S.length();
        // 获得next数组
        int[] next = new int[l];
        next[0] = 0; //没有公共前缀
        int j = 0;
        // AABAS
        // 01
        for (int i = 1; i < l; i++) {
            while (j > 0 && S.charAt(j) != S.charAt(i)) {
                j = next[j - 1]; //会退一步判断
                // :next[j - 1] 表示在 S[0...j-1] 这个子字符串中,最长的相同前缀和后缀的长度。如果 S[j] 和当前要比较的字符不匹配,这意味着 S[j] 不能作为前缀的一部分,因此需要找到一个更短的前缀,使得 S[0...next[j-1]] 和 S[i...] 能够匹配。
            }
            if (S.charAt(j) == S.charAt(i)) {
                j++;
            }
            next[i] = j; //验证到了这一步了。

        }
        return next;
    }

通过相同的思路使用next[]数组,
先while退回到合适的索引位置(针对S而言)
然后是if判断,S的索引++;
如果S的索引走到了S的末尾,那么说明已在T中找到等于S 的字串。

 import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 计算模板串S在文本串T中出现了多少次
     * @param S string字符串 模板串
     * @param T string字符串 文本串
     * @return int整型
     */
    public int kmp (String S, String T) {
        // write code here
        int sl=S.length();
        int tl=T.length();
        int count=0;
        int[] next=getNext(S);
        int j=0;
        for(int i=0;i<tl;i++)
        {
            while(j>0&&S.charAt(j)!=T.charAt(i))
            {
                j=next[j-1];
            }
            if(S.charAt(j)==T.charAt(i))
            {
                j++;
            }
            if(j==sl)
            {
                count++;
                j=next[j-1];//会退回去继续判断
            }

        }
        return  count;
    }
    public int[] getNext(String S) {
        int l = S.length();
        // 获得next数组
        int[] next = new int[l];
        next[0] = 0; //没有公共前缀
        int j = 0;
        // AABAS
        // 01
        for (int i = 1; i < l; i++) {
            while (j > 0 && S.charAt(j) != S.charAt(i)) {
                j = next[j - 1]; //会退一步判断
                // :next[j - 1] 表示在 S[0...j-1] 这个子字符串中,最长的相同前缀和后缀的长度。如果 S[j] 和当前要比较的字符不匹配,这意味着 S[j] 不能作为前缀的一部分,因此需要找到一个更短的前缀,使得 S[0...next[j-1]] 和 S[i...] 能够匹配。
            }
            if (S.charAt(j) == S.charAt(i)) {
                j++;
            }
            next[i] = j; //验证到了这一步了。

        }
        return next;
    }
}

第二次出现的j=next[j-1]; 不是在 “j 往前走的时候已经经历过了” 的位置停止,而是在每次找到匹配或确定不匹配后,为下一次可能的匹配做准备。将 j 设置为 next[j-1] 允许我们在 T 的下一个字符处继续搜索。这是因为 S[0…next[j-1]] 已经是一个匹配的前缀,我们可以从这个前缀的末尾开始,尝试与 T 中的下一个字符匹配。

避免重复匹配:如果我们将 j 重置为 0,那么我们会在 T 中重复计算已经匹配的 S 的部分。使用 next[j-1] 确保我们不会重复计算,并且可以继续从 T 的下一个字符开始搜索。

优化搜索过程:通过这种方式,KMP 算法可以在找到一次匹配后,快速跳到可能的下一个匹配位置,而不必从头开始搜索,从而提高搜索效率。

#2、DFS回溯剪枝法
在这里插入图片描述
想到了树,不同的子节点,深度遍历下去有不同的路径结果。
分析题意:

X.X.X.X 每个X∈[0,255], 要求不同出现0M,M∈[0,9]
剩余X的个数1<=字符串的长度<=剩余X的个数3(因为X是1到3位数组成)

树有不同的子节点,子节点的子节点…
即树的不同层代表着字符串s的剩余长度,即当前走到了s的哪一位了(索引位置cur)。

  public void dfs(String s,int cur)
      {
        if(tmp.size()==4&& cur==s.length())
        {
            res.add(tmp.get(0)+"."+tmp.get(1)+"."+tmp.get(2)+"."+tmp.get(3));
        }
        //jianzhi 
        if(s.length()-cur>3*(4-tmp.size()))//每段大于3
        {
            return;
        }
        if(s.length()-cur<4-tmp.size())//小于1
        {
            return;
        }
        int num=0;
        //当前节点的操作,即X.X.X.X中的一个X   
        //X:从s的某个位置(索引cur)开始,i∈[cur,cur+2],且i<s.length()
        for(int i=cur;i<cur+3&&i<s.length();i++)//一个一个数字的判断
        {//0,1,2
            num=num*10+(s.charAt(i)-'0');//数字
            //百十个位
            if(num<0||num>255)//数字越界了就不要了,

            {
                break;
            }
            //
            tmp.add(s.substring(cur,i+1));//截取【0,255】之间的数字
            //判断写一个位置上可能的X
            dfs(s,i+1);//继续判断
            tmp.remove(tmp.size()-1);//为啥?
            // 回溯允许算法“回到”上一个状态,重新考虑不同的数字组合。
            if(num==0)
            {
                break;//只能0.不能02|09这些
            }


        }
      }
import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param s string字符串 
     * @return string字符串ArrayList
     */
     ArrayList<String> res=new ArrayList<>();
    ArrayList<String> tmp=new ArrayList<>();
     
    public ArrayList<String> restoreIpAddresses (String s) {
        // write code here
        // 限制每一个[1,3]位置以及如果是3,那么数字小于255,否则,挪给别的,
        // >1则不能以0开头
        // 根据位数判断
        dfs(s,0);
        return res;

      }
      public void dfs(String s,int cur)
      {
        if(tmp.size()==4&& cur==s.length())
        {
            res.add(tmp.get(0)+"."+tmp.get(1)+"."+tmp.get(2)+"."+tmp.get(3));
        }
        //jianzhi 
        if(s.length()-cur>3*(4-tmp.size()))//每段大于3
        {
            return;
        }
        if(s.length()-cur<4-tmp.size())//小于1
        {
            return;
        }
        int num=0;
        for(int i=cur;i<cur+3&&i<s.length();i++)//一个一个数字的判断
        {//0,1,2
            num=num*10+(s.charAt(i)-'0');//数字
            if(num<0||num>255)//数字越界了就不要了,

            {
                break;
            }
            tmp.add(s.substring(cur,i+1));//截取【0,255】之间的数字
            dfs(s,i+1);//继续判断
            tmp.remove(tmp.size()-1);//为啥?
            // 回溯允许算法“回到”上一个状态,重新考虑不同的数字组合。
            if(num==0)
            {
                break;//只能0.不能02|09这些
            }


        }
      }
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Windows10/11家庭版开启Hyper-V虚拟机功能详解

Hyper-V是微软的一款虚拟机软件&#xff0c;可以使我们在一台Windows PC上&#xff0c;在虚拟环境下同时运行多个互相之间完全隔离的操作系统&#xff0c;这就实现了在Windows环境下运行Linux以及其他OS的可能性。和第三方虚拟机软件&#xff0c;如VMware等相比&#xff0c;Hyp…

Java版Flink使用指南——定制RabbitMQ数据源的序列化器

大纲 新建工程新增依赖数据对象序列化器接入数据源 测试修改Slot个数打包、提交、运行 工程代码 在《Java版Flink使用指南——从RabbitMQ中队列中接入消息流》一文中&#xff0c;我们从RabbitMQ队列中读取了字符串型数据。如果我们希望读取的数据被自动化转换为一个对象&#x…

white-space属性换行

white-space 属性可以控制元素中文本的换行方式。常用的取值有&#xff1a; normal&#xff08;默认值&#xff09;&#xff1a;根据容器的大小自动换行。nowrap&#xff1a;文本不进行换行&#xff0c;超过容器宽度时会溢出。pre&#xff1a;保留原始的空白符&#xff08;空格…

5.Python学习:面向对象

1.面向对象和面向过程的区别 以下五子棋为例&#xff1a; 2.类和实例 &#xff08;1&#xff09;类是抽象的模板&#xff0c;实例是根据模板创建出来的具体的对象 &#xff08;2&#xff09;比如人类就是一个类&#xff0c;刘亦菲就是人类的一个实例 2.1 新建类和类的实例…

【uniapp-ios】App端与webview端相互通信的方法以及注意事项

前言 在开发中&#xff0c;使用uniapp开发的项目开发效率是极高的&#xff0c;使用一套代码就能够同时在多端上线&#xff0c;像笔者之前写过的使用Flutter端和webview端之间的相互通信方法和问题&#xff0c;这种方式本质上实际上是h5和h5之间的通信&#xff0c;网上有非常多…

计算机的错误计算(二十五)

摘要 介绍&#xff08;不&#xff09;停机问题。给了一个算式&#xff0c;当计算机的输出为0时&#xff0c;一般需要提高计算精度继续计算&#xff0c;一直到获得非0值或有效数字。但是&#xff0c;由于事先不清楚算式的准确值是否为0或不为0&#xff0c;因此往往陷入两难境地…

LLM - Transformer 的 多头自注意力(MHSA) 理解与源码

欢迎关注我的CSDN:https://spike.blog.csdn.net/ 本文地址:https://spike.blog.csdn.net/article/details/140281680 免责声明:本文来源于个人知识与公开资料,仅用于学术交流,欢迎讨论,不支持转载。 在 Transformer 中,多头自注意力机制 (MHSA, Multi-Head Self-Attenti…

关系型数据库MySQL和时序数据库的区别?

时序数据库和关系型数据库是两种不同类型的数据库系统&#xff0c;它们在设计理念、存储结构、性能优化等方面有显著差异&#xff0c;以适应不同的应用场景和需求。具体对比如下&#xff1a; 数据存储结构 时序数据库&#xff1a;使用列式存储&#xff0c;每条记录通常包含时间…

Johnson Counter

目录 描述 输入描述&#xff1a; 输出描述&#xff1a; 参考代码 描述 请用Verilog实现4位约翰逊计数器&#xff08;扭环形计数器&#xff09;&#xff0c;计数器的循环状态如下。 电路的接口如下图所示。 输入描述&#xff1a; input clk , input …

力扣喜刷刷--day1

1.无重复字符的最长子串 知识点&#xff1a;滑动窗口 基本概念 窗口&#xff1a;窗口是一个连续的子序列&#xff0c;可以是固定长度或可变长度。滑动&#xff1a;窗口在数据序列上移动&#xff0c;可以是向左或向右。边界&#xff1a;窗口的起始和结束位置。 应用场景 字符…

YOLOv10改进 | Conv篇 | 利用DualConv二次创新C2f提出一种轻量化结构(轻量化创新)

一、本文介绍 本文给大家带来的改进机制是利用DualConv改进C2f提出一种轻量化的C2f&#xff0c;DualConv是一种创新的卷积网络结构&#xff0c;旨在构建轻量级的深度神经网络。它通过结合33和11的卷积核处理相同的输入特征映射通道&#xff0c;优化了信息处理和特征提取。Dual…

关于 off-by-one 的学习

pwn的功底还很浅&#xff0c;仅仅是记录自己学习的一点心得体会。 后续随着学习深入&#xff0c;还会补知识点和题目上来。 知识点 优秀的学习资料 关于off by null的学习总结 | ZIKH26 Chunk Extend and Overlapping | ctfwiki 一点理解 与off-by-one联系很紧密的就是上…

Fastapi在docekr中进行部署之后,uvicorn占用的CPU非常高

前一段接点小活&#xff0c;做点开发&#xff0c;顺便学了学FASTAPI框架&#xff0c;对比flask据说能好那么一些&#xff0c;至少并发什么的不用研究其他的asgi什么的&#xff0c;毕竟不是专业开发&#xff0c;能少研究一个东西就省了很多的事。 但是部署的过程中突然之间在do…

典型案例 | 基于全数字实时仿真的嵌入式DevOps解决方案

为丰富浙江省信息技术应用创新&#xff08;以下简称“信创”&#xff09;产业生态&#xff0c;在全社会各领域形成示范效应&#xff0c;浙江省经信厅联合省密码管理局开展2023年浙江省深化信创典型案例评选工作。 经过征集申报、专家评选、名单公示等程序&#xff0c;确定36个…

秒懂设计模式--学习笔记(6)【创建篇-建造者模式】

目录 5、建造者模式5.1 介绍5.2 建造步骤的重要性5.3 地产开发商的困惑5.4 建筑施工方5.5 工程总监5.6 项目实施5.7 建造者模式的各角色定义5.8 建造者模式 5、建造者模式 5.1 介绍 建造者模式&#xff08;Builder&#xff09;又称为生成器模式&#xff0c;主要用于对复杂对象…

20.呼吸灯:利用PWM控制小灯在相同时间段内的不同占空比

&#xff08;1&#xff09;设计一段代码&#xff0c;实现led灯在一秒内由完全熄灭到完全点亮&#xff0c;在第二秒由完全点亮转为完全熄灭&#xff0c;循环往复。 &#xff08;2&#xff09;Verilog代码&#xff1a; module breath_led(clk,reset_n,led);input clk;input res…

Open3D 计算点云的欧式距离

目录 一、概述 1.1欧式距离定义 1.2作用和用途 二、代码实现 2.1关键函数 2.2完整代码 三、实现效果 3.1原始点云 3.2处理后点云 一、概述 在Open3D中&#xff0c;compute_point_cloud_distance函数用于计算两个点云之间的距离。具体来说&#xff0c;它计算的是源点云…

进程 VS 线程(javaEE篇)

&#x1f341; 个人主页&#xff1a;爱编程的Tom&#x1f4ab; 本篇博文收录专栏&#xff1a;JavaEE初阶&#x1f449; 目前其它专栏&#xff1a;c系列小游戏 c语言系列--万物的开始_ 等 &#x1f389; 欢迎 &#x1f44d;点赞✍评论⭐收藏&#x1f496;三连支…

一.4 处理器读并解释储存在内存中的指令

此刻&#xff0c;hello.c源程序已经被编译系统翻译成了可执行目标文件hello&#xff0c;并被存放在硬盘上。要想在Unix系统上运行该可执行文件&#xff0c;我们将它的文件名输入到称为shell的应用程序中&#xff1a; linux>./hello hello, world linux> shell是一个命令…

YOLOv10改进 | 添加注意力机制篇 | 添加FocusedLinearAttention助力yolov10实现有效涨点(含二次创新PSA机制)

一、本文介绍 本文给大家带来的改进机制是Focused Linear Attention&#xff08;聚焦线性注意力&#xff09;是一种用于视觉Transformer模型的注意力机制(但是其也可以用在我们的YOLO系列当中从而提高检测精度)&#xff0c;旨在提高效率和表现力。其解决了两个在传统线性注意力…