深入理解JAVA字符串以及KMP算法深度详解

1.字符串抽象数据类型

public class test3  {
    int length()//返回串长度
    char charAt(int i )//返回第i个字符
    void setCharAt(int i,char ch)//返回第i个字符为ch
    substring(int begin,int end)//返回序号begin至end-1的子串
    concat(String s) //返回this与s串连接生成的串
    String delete(int begin,int end)//删除从begin到end-1的子串
    boolean equals(Object obj)//比较this和obj引用是否相等
    int compareTo(String s)//比较this与s串的大小,返回两者的差值
    int indexOf(String pattern)//返回首个与模式串pattern匹配的子串序号
    void removeAll(String partern)//删除所有与pattern匹配的子串
}

2.字符串和整数相互转换的方法

    //将整数转化成字符串
    int number =123;
    String numberAsString=String.valueOf(number);
    String numberAsString2=Integer.toString(number);

一般都是使用valueOf方法来进行整数转换,应为valueOf可以接收多种类型的参数,比如(int,long,float,double )等,但是toString只能接收int类型的参数。

    //把String转换成int型
    String s ="123";
    int i =Integer.parseInt(s);

3.字符串的顺序存储结构和实现

1.常量字符串

JAVA字符串类主要有String常量字符串类,StringBuffer变量字符串类等。这两种字符串类都采用顺序存储结构,能够存储任意长度的字符串,实现串的基本操作,并且能够识别序号越界等错误。

Strng字符串是一个类,属于引用数据类型。提供构造串对象,求串长度,取字符,求子串,连接串,比较相等,比较大小等操作。若charAt(i),subString(begin,end)方法参数的序号越界,则排除StringIndexOutOfBoundException字符串序号越界异常。

2.String类的特点

  1. String类是最终类,不能被继承
  2. String类是以常量串方式存储和实现字符串操作
  3. 声明字符数组是最终变量,串中各字符是只读的。当构造串对象时,对字符数组进行一次赋值,其后不能更改。String类只提供了取字符操作charAt(i),不提供修改字符,插入串和删除子串操作。
  4. 构造串,求子串和连接串的操作都是深拷贝,重新申请字符串占用的字符数组,

3.比较串大小

String类声明的compareTo()方法比较两个字符串大小,返回两者之间的差值,分别为以下三种情况:

1.若两字符串s1、s2相等,则s1.compareTo(s2)返回0。

2.若两字符串s1、s2不等,则从头开始依次将两串中的对应字符进行比较,当首次遇到两个不同字符时,s1.compareTo(s2)返回这两个不同字符的差值,

s1.charAt(i)-s2.charAt();//i为首次遇到两个不同字符的位置

3.两个字符串s1和s2,若s1是s2的前缀子串,或s2是s1的前缀子串,则s1.compareTo(s2)返回两者长度的差值

例如,"abcde".compareTo("ab")返回3。

实现compareTo()方法如下,比较两个字符串的大小,返回两者之间的差值。

public int compareTo(MyString s){
for(int i =0;i<this.value&&i<s.value.length;++){
    if(this.value[i]!=s.value[i])
         return this.value[i]-s.value[i];
     return this.values.length-s.value.length;
}
}

4.使用String串

使用String串的求子串和连接串操作,实现串的插入,删除功能。

1.插入串

设有String串s1.s2,在s1的i位置插入s2串,返回插入后的串,调用语句如下

String s1 ="a",s2 ="xyz";
int i =3;
String s3 =s1.substring(0,i)+s2+s1.substring(i);
2.删除子串

设有串s,删除串s中序号从begin到end-1子串,返回删除后的子串,调用语句如下:

int begin=3, end =6;
String s4 =s.substring(0,begin)+s.substring(end);
3.反转字符串的reverse的操作:
public class ReverseString {
    public static String reverse(String str) {
        if (str == null || str.isEmpty()) {
            return str;
        }
        return reverse(str.substring(1)) + str.charAt(0);
    }

    public static void main(String[] args) {
        String originalString = "Hello, World!";
        String reversedString = reverse(originalString);
        System.out.println("Original String: " + originalString);
        System.out.println("Reversed String: " + reversedString);
    }
}
//输出:
Original String: Hello, World!
Reversed String: !dlroW ,olleH

这就是使用递归实现的 reverse 方法。它以一种简洁的方式反转字符串,尽管这种方法在处理长字符串时可能会导致性能问题。对于长字符串,使用 StringBuilder 或 StringBuffer 通常更为高效

public class ReverseString {
    public static void main(String[] args) {
        String originalString = "Hello, World!";
        String reversedString = new StringBuilder(originalString).reverse().toString();
        System.out.println("Original String: " + originalString);
        System.out.println("Reversed String: " + reversedString);
    }
}

字符的模式串匹配

BF模式算法匹配模式

设有两个串:目标串target和模式串pattern,在target目标串中查找与pattern模式串相等的一个子串并确定改子串位置的操作称为串的模式匹配。两个子串相等是指,各对应字符相同且长度相同。匹配结果有两种:如果target中存在与pattern相等的子串,则匹配成功,获得该匹配子串在target中的位置,否则匹配失败。

KMP模式匹配算法

KMP算法,全称Knuth-Morris-Pratt字符串搜索算法,是一种高效的字符串搜索算法。它由Donald Knuth、Vaughan Pratt和James H. Morris在1977年共同发明。KMP算法的核心思想是利用部分匹配表(也称为前缀函数或部分匹配表)来避免在文本中重复搜索已经匹配过的字符。

本篇以主串为ababcabcacbab,模式串为abcac为例

先了解一些基本概念:

  1. 前缀:除最后一个字符意外,字符串的所有头部子串。
  2. 后缀:除第一个字符以外,字符串的所有的尾部子串。

目的:需要找到的是每个子串前缀和后缀相等的最长的前缀和后缀长度。

下面是一个例子:

子串前缀后缀
a
abab
abcab,abc,c
abcaabc,ab,abca,ca,a
abcacabca,abc,ab,abcac,caca,ac,c

所以,字符串abcac的最长相等前后端长度是00010,将这个长度写成数组形式,得到对应的部分匹配值[0,0,0,1,0]

模拟匹配过程

我们将模拟abcac和主串ababcabcacba进行匹配

第一趟:

主串指针len=2,模式串指针i=2时,模式串的c和主串的a匹配失败。已经匹配的字符串是ab,查看前缀表,prefix[1]=0,说明ab前缀和后缀没有相等的,所以下一趟模式串要退回到第一个字符重新比较。

下标01234567891011
主串ababcabcacba
模式串abc

第二趟:

在第二次匹配之前,子串匹配索引j直接跳到第一匹配的相同前缀串的最长匹配长度的索引位置上即j=2,主串指针len=6,模式串指针i=4时,模式串的c和主串b匹配失败。已经匹配的字符串是abca前缀和后缀有一个字符相等,所以下一趟模式串要退回到第二个字符开始重新比较,也就是退回到模式串下标为1的位置

下标01234567891011
主串ababcabcacba
模式串abcac

第三趟:

主串指针len=6,模式串指针i=0时,模式串的a和主串b匹配失败。查看前缀表,prefix[0]=0,说明前缀和后缀没有相等的,因为当前与主串比较的就是模式串的第一个字符,所以,将主串移动到下一个位置,与模式串的第一个字符进行比较。

下标01234567891011
主串ababcabcacba
模式串abcac

模式串全部比较完成,匹配成功,整个匹配过程中,主串始终没有回退,所以KMP算法的时间复杂度是O(m+n)。

next数组

在KMP算法中,next数组用于记录模式串中每个位子的最长相同的前缀和后缀的长度

next数组计算可以避免在搜索过程中的无效比较,因为如果当前字符不匹配,算法可以利用next数组直接跳到下一个可能匹配位置,而不是回到文本的最早位置。那么next是怎么计算的呢?

以abcabc为例:

j012345
模式串abcabc
最长相同前后子串长度-100012

 用abcac为讲解prefix与next之间的关系:

下标01234
字符串abc

a

c
前缀表00010
next-10001

将前缀整体右移一位,然后将空出来的第一位用-1补充,就得到了next数组。

这样子,当模式串和主串匹配失败的时候,直接查看当前匹配失败的字符的前缀表就可以了,而不是查看匹配失败字符前一个字符的前缀表了。

还是以字符串abcac与主串ababcabcacba匹配为例:

当第一趟匹配失败的时候,主串指针len=2,模式串指针i=2时,模式串的c和主串a匹配失败。查看前缀表,prefix(2)=0,说明ab前缀和后缀没有相等的,所以下一趟模式串要退回到第一个字符重新比较,也就是退到模式串pattern的下标0的位置

下标01234567891011
主串ababcabcacba
模式串abc

这里是从-1开始存储和计算next数组的没所以此时next数组的含义是指:当模式串的第i个字符与主串发生匹配失败时,就退回到模式串的next[i]重新与主串进行匹配。当然可以从0开始存储和计算next数组的。

下标01234
字符串abc

a

c
next01112
 KMP算法的代码实现
public class KMPAlgorithm {
    private int[] computeTemporaryArray(char pattern[]){
        int[] lps =new int[pattern.length];//创建一个名为lps的整数数组,其长度与pattern数组相同。这个数组将用于存储最长公共前后缀的长度
        int index =0;//用于在lps数组中跟踪当前的最长公共前后缀的长度。
        for (int i =1;i<pattern.length;i++){//开始一个循环,从数组的第二个元素开始(索引为1),直到数组的末尾。
            if (pattern[i]==pattern[index]){
                lps[i]=index+1;
                index++;
                i++;
            }else{
                if (index!=0){
                    index =lps[index-1];
                }else{
                    lps[i]=0;
                    i++;
                }
            }
        }
        return lps;
    }
    public boolean KMP(char[] text,char[] pattern){
        int[] lps =computeTemporaryArray(pattern);
        int i =0;
        int j =0;
        while (i<text.length&&j<pattern.length){
            if (text[i]==pattern[i]){
                i++;
                j++;
            }
        }
        if (j==pattern.length){
            return true;
        }else if(i<text.length&&text[i]!=pattern[j]){
            if (j!=0){
                j=lps[j-1];
            }else{
                i=i+1;
            }
        }
        return false;
    }

    public static void main(String[] args) {
        KMPAlgorithm kmp =new KMPAlgorithm();
        String txt ="ABABDABACDABABCABAB";
        String pat="ABABCABAB";
        char[] text =txt.toCharArray();
        char[] pattern=pat.toCharArray();
        boolean result =kmp.KMP(text,pattern);
        System.out.println("The pattern is found in the text:"+result);
    }

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

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

相关文章

LLM - 卷积神经网络(CNN)

1. 卷积神经网络结构&#xff1a;分为输入层&#xff0c;卷积层&#xff0c;池化层&#xff0c;全连接层&#xff1b; &#xff08;1&#xff09;首先进入输入层&#xff0c;对数据数据进行处理&#xff0c;将输入数据向量化处理&#xff0c;最终形成输入矩阵。 &#xff08;…

C++ 什么是虚函数?什么是纯虚函数,以及区别?(通俗易懂)

&#x1f4da; 当谈到虚函数时&#xff0c;通常是指在面向对象编程中的一种机制&#xff0c;它允许在派生类中重写基类的函数&#xff0c;并且能够通过基类指针或引用调用派生类中的函数。 目录 前言 &#x1f525; 虚函数 &#x1f525; 纯虚函数 &#x1f525; 两者区别…

用 Echarts 画折线图

https://andi.cn/page/621503.html

leetcode每日一题-3033. 修改矩阵

题目描述&#xff1a; 解题思路&#xff1a;简单题目&#xff0c;思路非常直接。对列进行遍历&#xff0c;记录下最大值&#xff0c;然后再遍历一遍&#xff0c;把-1替换为最大值。需要注意的是进行列遍历和行遍历是不同的。 官方题解&#xff1a; class Solution { public:v…

VRay渲染有什么技巧?渲染100邀请码1a12

渲染是视觉行业非常重要的一环&#xff0c;没有渲染就没有效果图&#xff0c;常用的渲染器有Vray&#xff0c;而Vray渲染有很多技巧&#xff0c;可以让渲染更快更省&#xff0c;下面我们总结下。 1、删除无用对象 检查场景&#xff0c;看是否有一些不需要渲染的物体和灯光&am…

将大型语言模型模块化打造协作智能体

B UILDING C OOPERATIVE E MBODIED A GENTS MODULARLY WITH L ARGE L ANGUAGE M ODELS 论文链接&#xff1a; https://arxiv.org/abs/2307.02485https://arxiv.org/abs/2307.02485 1.概述 在去中心化控制及多任务环境中&#xff0c;多智能体合作问题因原始感官观察、高昂…

绝区肆--2024 年AI安全状况

前言 随着人工智能系统变得越来越强大和普及&#xff0c;与之相关的安全问题也越来越多。让我们来看看 2024 年人工智能安全的现状——评估威胁、分析漏洞、审查有前景的防御策略&#xff0c;并推测这一关键领域的未来可能如何。 主要的人工智能安全威胁 人工智能系统和应用程…

el-date-picker 设置默认值为当前日期

this.listQuery.Date new Date().toISOString().substr(0, 10); <el-date-picker v-model"listQuery.Date" format"yyyy-MM-dd" value-format"yyyy-MM-dd" type"date" placeholder"选择日期" change"getList()&qu…

Java语言程序设计篇一

Java语言概述 Java语言起源编程语言最新排名名字起源Java语言发展历程Java语言的特点Java虚拟机垃圾回收Java语言规范Java技术简介Java程序的结构Java程序注意事项&#xff1a;注释编程风格练习 Java语言起源 1990年Sun公司提出一项绿色计划。1992年语言开发成功最初取名为Oak…

Blender新手入门笔记收容所(一)

基础篇 基础操作 视角的控制 控制观察视角&#xff1a;鼠标中键平移视图&#xff1a;Shift鼠标中键缩放视图&#xff1a;滚动鼠标中键滚轮 选中物体后&#xff1a;移动物体快捷键G&#xff0c;移动后单击鼠标就会定下来。 进入移动状态后&#xff1a;按Y会沿着Y轴移动进入移动…

成人高考本科何时报名-深职训学校帮您规划学习之路

你有想过继续深造自己的学历吗&#xff1f;也许你已经工作多年&#xff0c;但总觉得学历是一块心病&#xff0c;想要通过成人高考本科来提升自己。不用着急&#xff0c;今天我们来聊一聊成人高考本科的报名时间&#xff0c;以及深职训学校如何帮助你顺利完成报名。 深圳成人高…

2024上半年网络工程师考试《应用技术》试题一

阅读以下说明&#xff0c;回答问题。 【说明】 MPLS基于(1)进行转发&#xff0c;进行MPLS标签交换和报文转发的网络设备称为(2)&#xff0c;构成MPLS域(MPSDomain)。位于MPLS域边缘、连接其他网络的LSR称为(3),区域内部的LSR称为核心LSR(CoreLSR)IP报文进入MPLS网络时&#xf…

文件管理下:文件函数的学习

前言 Hello,小伙伴们你们的作者君又来了&#xff0c;上次我们简单介绍了文件的坐拥并简单提到了数据的读取&#xff0c;和C语言的默认流的作用&#xff0c;今天我将继续带领大家探索文件的奥秘&#xff0c;大家准别好了吗&#xff1f; 在内容开始之前还是按照惯例&#xff0c…

Alt与Tab切换窗口时将Edge多个标签页作为一个整体参与切换的方法

本文介绍在Windows电脑中&#xff0c;使用Alt与Tab切换窗口时&#xff0c;将Edge浏览器作为一个整体参与切换&#xff0c;而不是其中若干个页面参与切换的方法。 最近&#xff0c;需要将主要使用的浏览器由原本的Chrome换为Edge&#xff1b;但是&#xff0c;在更换后发现&#…

Python爬虫系列-让爬虫自己写爬虫(半自动化,代替人工写爬虫)

现在的PC、手机客户端等终端设备大量使用了网页前后端技术&#xff0c;另外主流的网站也会经常会更新&#xff0c;导致以前一个月更新一次爬虫代码&#xff0c;变成了天天需要更新代码&#xff0c;所以自动化爬虫技术在当前就显得特别重要&#xff0c;最近我也是在多次更新某个…

Java | Leetcode Java题解之第220题存在重复元素III

题目&#xff1a; 题解&#xff1a; class Solution {public boolean containsNearbyAlmostDuplicate(int[] nums, int k, int t) {int n nums.length;Map<Long, Long> map new HashMap<Long, Long>();long w (long) t 1;for (int i 0; i < n; i) {long i…

【Java探索之旅】初识多态_概念_实现条件

文章目录 &#x1f4d1;前言一、多态1.1 概念1.2 多态的实现条件 &#x1f324;️全篇总结 &#x1f4d1;前言 多态作为面向对象编程中的重要概念&#xff0c;为我们提供了一种灵活而强大的编程方式。通过多态&#xff0c;同一种操作可以应用于不同的对象&#xff0c;并根据对象…

【Python迭代器探秘】:揭秘迭代器与生成器的魔法,掌握高效循环的艺术

文章目录 一、迭代器的基本概念1.1 迭代器优点1.2 迭代器的编写方法1.3 python内置迭代器函数1.4 小结1.5 迭代器对象与迭代对象1.5.1 区别1. 迭代对象2. 迭代器对象3. 小结 1.5.2 方法区分 二、生成器基本概念1. 生成器函数2. 生成器表达式 一、迭代器的基本概念 迭代器是Pyt…

一.2.(2)基本共射放大电路组成、工作原理;

1.基本共射放大电路组成 共什么取决于输入输出&#xff0c;共剩下的那一极 2.工作原理 输入信号ui通过电容C1加到三极管的基 极&#xff0c;引起基极电流iB的变化&#xff0c;iB的变化又使集电极电流ic发生变 化&#xff0c;且ic的变化量是iB变化量的β倍。由于有集电极电压&…

【数据结构】05.双向链表

一、双向链表的结构 注意&#xff1a;这里的“带头”跟前面我们说的“头节点”是两个概念&#xff0c;带头链表里的头节点&#xff0c;实际为“哨兵位”&#xff0c;哨兵位节点不存储任何有效元素&#xff0c;只是站在这里“放哨的”。 “哨兵位”存在的意义&#xff1a;遍历循…