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

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.mfbz.cn/a/783157.html

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

相关文章

四川蔚澜时代电子商务有限公司持续领跑抖音电商

在当今这个数字化飞速发展的时代&#xff0c;电子商务已成为推动经济增长的重要引擎。而在众多电商平台中&#xff0c;抖音电商以其独特的社交属性和年轻化的用户群体&#xff0c;逐渐崭露头角。四川蔚澜时代电子商务有限公司正是这股潮流中的佼佼者&#xff0c;他们专注于抖音…

创建一个AXIS的初始IP核

参考自&#xff1a;https://www.cnblogs.com/milianke/p/17936380.html 以该博主文章为主&#xff0c;本文章做补充。 注意的点&#xff1a; edit ip 在导出axis的主机和从机的时候&#xff0c;记得选择edit ip&#xff0c;这样才能看到从机和主机的源代码&#xff0c;然后…

2024平价蓝牙耳机哪个牌子好?盘点热门平价蓝牙耳机推荐

2024年来&#xff0c;蓝牙耳机市场逐渐走向平价&#xff0c;这使得越来越多的消费者能够轻松拥有一副高性价比的蓝牙耳机。然而&#xff0c;在如此丰富的选择中&#xff0c;2024平价蓝牙耳机哪个牌子好&#xff1f;成为了许多人的烦恼。为了帮助大家更好地了解市场上的热门产品…

8、开发与大模型对话的独立语音设备

一、设计原理 该系统的核心部分主要由ESP32-WROVER开发板和ESP32-CAM摄像头、MAX9814麦克风放大器模块、MAX98357功放、声音传感器和SU-03T语音识别芯片构成。通过使用ESP32-WROVER开发板,用户可以实现通过语音与ai进行交互并进行人脸识别。 系统中,从外部输入电源中获取电源…

HTML5使用<output>标签:显示一些计算结果

HTML5 提供的 output 标签&#xff0c;用于显示出一些计算的结果或者脚本的其他结果。output 标签必须从属于某个表单&#xff0c;也就是说&#xff0c;必须将 output 标签写在表单内部&#xff0c;或者在该元素中添加 form 属性。 output 标签语法&#xff1a; <output f…

盘点2024年10款超级好用的项目管理软件,建议收藏!

今天猴哥整理并分享国内外使用最广泛的10大项目管理工具软件&#xff0c;同时探讨如何选择适合自己的项目管理工具所需考虑的要素。在国内外市场上&#xff0c;有非常多的项目管理软件可供选择。然而&#xff0c;逐一尝试这些软件将耗费大量时间&#xff0c;因此需要寻找更好更…

vue3中使用 tilwindcss报错 Unknown at rule @tailwindcss

解决方法&#xff1a; vscode中安装插件 Tailwind CSS IntelliSense 在项目中的 .vscode中 settings.json添加 "files.associations": {"*.css": "tailwindcss"}

基于CentOS Stream 9平台搭建MinIO以及开机自启

1. 官网 https://min.io/download?licenseagpl&platformlinux 1.1 下载二进制包 指定目录下载 cd /opt/coisini/ wget https://dl.min.io/server/minio/release/linux-amd64/minio1.2 文件赋权 chmod x /opt/coisini/minio1.3 创建Minio存储数据目录&#xff1a; mkdi…

我是售前工程师转大模型了,不装了我摊牌了

有无售前工程师的朋友&#xff0c;心里的苦谁懂呀&#xff0c;售前工程师是项目开发人员与业务销售人员的桥梁&#xff0c;在业务销售人员眼中&#xff0c;他们是技术人员&#xff0c;在项目实施中的开发人员眼中&#xff0c;他们是专注技术的销售人员&#xff0c;在用户眼中&a…

vue3关于在线考试 实现监考功能 推流拉流

vue3 关于在线考试 实现监考功能&#xff0c; pc端考试 本质是直播推流的功能 使用腾讯云直播: 在线文档 index.html <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><link rel"icon" href"/f…

linux 安装Openjdk1.8

一、在线安装 1、更新软件包 sudo apt-get update 2、安装openjdk sudo apt-get install openjdk-8-jdk 3、配置openjdk1.8 openjdk默认会安装在/usr/lib/jvm/java-8-openjdk-amd64 vim ~/.bashrc export JAVA_HOME/usr/lib/jvm/java-8-openjdk-amd64 export JRE_HOME${J…

数据分析入门指南Excel篇:各类Excel函数概览与详解(二)

在当今数字化时代&#xff0c;数据已成为推动业务决策和创新的关键因素。而表格结构数据&#xff0c;作为最常见的数据存储形式之一&#xff0c;广泛应用于财务、物流、电商等多个领域。本文将基于提供的材料文本&#xff0c;深入探讨表格数据的处理与分析&#xff0c;特别是通…

【云原生】Kubernetes部署EFK日志分析系统

Kubernetes部署EFK日志分析系统 文章目录 Kubernetes部署EFK日志分析系统一、前置知识点1.1、k8s集群应该采集哪些日志&#xff1f;1.2、k8s比较流行的日志收集解决方案1.3、fluentd、filebeta、logstash对比分析1.3.1、Logstash1.3.2、Filebeat1.3.3、fluentd 1.4、EFK工作原理…

STM32自己从零开始实操08:STM32主控原理图

由于老师使用的各引脚分门别类的单片机原理图我没有找到&#xff0c;我使用是引脚按顺序摆放的&#xff0c;不方便一个模块一个模块截图展示&#xff0c;所以这部分使用老师的原理图。 一、电源 1.1电源的介绍 1.1.1数字电源和地&#xff08;VDD和VSS&#xff09; 数字电源…

修改CentOS7.9跟Unbantu24的ip地址

修改CentOS的IP地址 ip addr 查看IP地址 cd /etc/sysconfig/network-scripts ls vi ifcfg-ens33修改ip地址跟干网关地址 TYPE"Ethernet" PROXY_METHOD"none" BROWSER_ONLY"no" BOOTPROTO"static" DEFROUTE"yes" IPV4_FA…

项目2:API Hunter 细节回顾 -2

一. 接口上线/下线功能 接口的上线和下线是由管理员负责进行的。 上线接口&#xff0c;即发布接口。首先需要判断接口是否存在&#xff0c;然后判断接口是否可调用。如果可以调用&#xff0c;就修改数据库中该接口的状态字段为 1&#xff0c;代表发布&#xff0c;默认状态为 …

精美个人博客 付费搭建

博客演示地址&#xff1a;http://gavana.top/ 1、前端博客页 2、后端管理页 此项目原作者已开源&#xff0c;地址&#xff1a;Naccl/NBlog: &#x1f353; Spring Boot Vue 前后端分离博客系统 https://naccl.top (github.com) 可以自己搭建&#xff0c;我只是负责搭建起可直…

【Java13】包

“包”这个机制&#xff0c;类似于分组。主要作用是区分不同组内的同名类。例如&#xff0c;高三三班有一个“王五”&#xff0c;高二八班也有一个“王五”。高三三班和高三八班就是两个不同的包。 Java中的包&#xff08;package&#xff09;机制主要提供了类的多层命名空间&…

被全球数千企业应用的TOGAF®标准,不仅仅是IT框架

2022 年 4 月 25 日&#xff0c;The Open Group 发布了 TOGAF标准第10版。这不仅仅是 The Open Group 的重要里程碑&#xff0c;也是整个企业架构行业和所有从业者的重大利好。作为企业架构师的首选标准&#xff0c;TOGAF一直以来都受到人们的欢迎。对此&#xff0c;第10版必须…

Java异常详解及自定义异常

认识异常&#xff0c;掌握异常处理主要的5个关键字&#xff1a;throw、try、catch、final、throws并掌握自定义异常 目录 1、异常概念与体系结构 1、1异常的概念 1、2异常体系结构 1、3异常的分类 编译时异常&#xff1a; 运行时异常 &#xff1a; 2、异常处理 2、1防御式…