今天被问到Java字符串搜索,中午抽空研究了String的源码。
int indexOf(String str)
核心查找代码:
for (int i = sourceOffset + fromIndex; i <= max; i++) { /* Look for first character. */ if (source[i] != first) { while (++i <= max && source[i] != first); } /* Found first character, now look at the rest of v2 */ if (i <= max) { int j = i + 1; int end = j + targetCount - 1; for (int k = targetOffset + 1; j < end && source[j] == target[k]; j++, k++); if (j == end) { /* Found whole string. */ return i - sourceOffset; } } }
这段代码的简单思想是:从源字符串的索引0开始,按字符查找,直到最大索引max(max=源字符串长度 - 子字符串长度),找到和子串第一个字符(first)匹配的字符,记下索引位置并且存放到变量i中;
接下去判断i是否超出max,如果超出,则直接返回-1,查找结束;
如果i小于max,则源字符串索引i加1,子字符串索引k也加1,然后比对这两个索引对应的字符:
如果相等,两个字符串的索引再各自加1继续循环;
如果不相等,跳出循环;
继续执行下面的代码: 如果j==end意味着子串遍历完了(也就是在源字符串查找到了子串),返回查找到的子串索引,程序结束;
如果不满足j==end,则源字符串的索引i++,然后重新执行上面过程,直到源字符串遍历到最大索引max(这中间可能找到子串,提前返回);
这种字符串查找的算法谈不上高效,但是对于小字符串来说应该够用了;
对于字符串查找场景较多,并且字符串很长的情况(可能需要查找的子串靠近源字符串的后半部分),这个方法可能效率不够高;
接着写 int lastIndexOf(String str),先上源码:
int strLastIndex = targetOffset + targetCount - 1; char strLastChar = target[strLastIndex]; int min = sourceOffset + targetCount - 1; int i = min + fromIndex; startSearchForLastChar: while (true) { while (i >= min && source[i] != strLastChar) { i--; } if (i < min) { return -1; } int j = i - 1; int start = j - (targetCount - 1); int k = strLastIndex - 1; while (j > start) { if (source[j--] != target[k--]) { i--; continue startSearchForLastChar; } } return start - sourceOffset + 1; }
查找的原理大致和indexOf相同,只不过lastIndexOf是从尾部开始查找的,并且中间的一些细节还是和indexOf不同的。
上面这段代码的主要意思是:
初始计算部分:
计算子串的最后一个字符,存入变量strLastChar中;
计算源字符串查找的终点索引,存入变量min;
计算源字符串的查找起点索引,存入变量i;
进入第一个while循环:
while (i >= min && source[i] != strLastChar) { i--; }
这段代码是在源字符串找到和子串最后一个字符相等的字符,把他的索引存入变量i(从尾部开始查找)
如果索引i小余min,意味着已经不在上面规定的查找范围之内了,直接返回-1;
如果索引i合法,那么确定源字符串的查找范围(起点j=i-1,终点start=起点-子串长度+1)【源码中终点的变量是start,作者觉得这是查找的终点,请注意区分】
确定子串的查找起点k=子串最后一个字符索引-1
用源字符串的索引j处的字符和子串索引k处的字符比较,并且j和k各自减1:
如果字符相等,则继续执行上面的比较,直到索引j递减到j>start(索引j超出了查找的终点start),则跳出循环继续往下执行;
如果字符不相等,则程序跳转到锚点startSearchForLastChar处,按照上面的逻辑继续执行;
如果if (source[j--] != target[k--])的比对一直相等,并且把while (j > start)循环执行完了,意味着在源字符串找到了子串(只需要找到第一个就可以了,当然是从末尾开始找的),程序返回子串的索引。
对于很长的字符串查找的优化,推荐一篇文章: KMP子字符串查找算法分析与实现
全文完。
相关推荐
这种算法的主要思想是创建一个动态更新的字典,字典中的条目是输入字符串中的已编码子串。 在Java环境中实现LZ78算法,首先我们需要理解其基本步骤: 1. 初始化:创建一个空的字典,通常用一个数组或哈希表表示,...
字符串反转的基本思想是从字符串的最后一个字符开始,依次向前获取每个字符,直到获取到第一个字符为止。如果使用递归来实现这个过程,那么可以定义一个递归函数,该函数接受一个字符串作为输入,并返回一个新的反转...
根据给定的文件信息,本文将详细介绍如何使用Java实现基于字符串的余弦相似度算法,并应用于推荐系统中。 ### 一、引言 在推荐系统领域,为了衡量两个字符串之间的相似性,通常会采用多种算法,其中余弦相似度算法...
其核心思想是通过遍历整个字符串,逐个检查每个字符是否与目标字符匹配,如果匹配则计数器加一。例如,在给定的代码片段中,通过以下C#代码实现了对字符“A”的计数: ```csharp int c1 = 0; for (int i = 0; i ; i...
在C++编程中,标准库提供了`std::string`类来处理字符串,但它在某些情况下可能无法满足所有需求。为了增强其功能,开发者有时会选择扩展这个基础类,以实现更高级的操作,比如在控制台上输出彩色字符串。在给定的...
括号匹配是计算机科学中一个基础且关键的问题,主要用来检查一个字符串中的左右括号是否正确配对。例如,我们常见的括号有大括号`{}`、小括号`()`、中括号`[]`。 在这个描述中提到的程序,是利用栈来检查字符串中的...
在Java语言中,我们可以使用String类的split()方法来将字符串分割成数组,然后使用StringBuilder类来将数组中的元素连接起来。 3. 事件处理:在图形用户界面中,我们需要处理用户的交互事件,例如点击按钮时需要...
在编程领域,字符串操作是日常...它们虽然语法不同,但核心思想是一致的:遍历字符串,遇到目标字符时记录下标并累加计数。通过这种方式,我们可以高效地处理这类问题,无论是在简单的命令行应用还是复杂的软件系统中。
这里我们利用了Java字符串的`substring`方法,它会创建一个新的字符串,包含从原始字符串的起始索引到结束索引之间的字符。在每次递归调用中,字符串的长度都会减少1,直到达到基本情况。 递归调用的过程如下: 1....
Java String 字符串常量池解析 Java 中的字符串常量池是一种为了提高性能和减少内存开销的机制。它是 JVM 实例化字符串常量时进行的一些优化,主要是为了减少字符串对象的创建和存储。 字符串常量池的设计思想是...
字符串在许多编程语言中都有专门的数据类型来表示,例如Python中的str、Java中的String、C++中的std::string等。字符串类通常包含以下属性和方法: 1. **属性**: - 长度:表示字符串中字符的数量。 - 内容:存储...
字符串逆序的基本思想是将字符串的最后一个字符移动到最前面,然后依次对其他字符进行类似的操作,直到整个字符串的字符顺序完全反转。在大多数编程语言中,我们可以通过遍历字符串并利用数组或集合的操作来实现这个...
总之,利用Java中的栈数据结构实现字符串逆序输出是一种常见的练习,它能帮助开发者更好地理解和掌握栈的工作原理以及其在实际问题中的应用。这个例子展示了如何通过自定义数据结构(`MyStack`)来实现栈的功能,...
在Java编程中,实现字符串匹配并寻找两个字符串的最大公共子串是一项常见的任务,尤其是在文本处理、数据比较和信息检索等领域。本示例介绍了一种基于二维数组(也称为动态规划矩阵)的算法来解决这个问题。 最大...
在Java中,字符串是由`String`类表示的,该类提供了多种方法来操作字符串,包括截取。对于基本的ASCII字符,我们可以直接使用`substring`方法来轻松完成截取任务。但当字符串包含非ASCII字符时,就需要特别注意了。...
字符串对象通常使用`String`类表示,而`StringBuilder`或`StringBuffer`类用于构建和修改字符串,特别是在需要多次修改字符串的操作中,这两个类的效率更高。 2. **字符数组和字符串的关系**:在Java中,字符串可以...
在本压缩包“java-leetcode题解之第443题压缩字符串.zip”中,包含的是针对LeetCode平台上的第443题“压缩字符串”的Java解决方案。LeetCode是一个在线编程挑战平台,它提供了各种算法题目,帮助程序员提升技能并...
在`String`的处理中,`String Pool`正是利用了`Flyweight`模式的思想,避免了内存中存储大量重复字符串的开销。 ### 结论 深入理解Java中`String`的处理机制对于避免陷阱至关重要。`String`的不可变性和`String ...
该算法的核心思想是通过双重循环遍历两个字符串,逐个字符进行比较,以找到最长的匹配子串。 - **初始化**:首先设置两个指针`flag1`和`flag2`,分别指向`str1`和`str2`的第一个字符。同时初始化最大子串的长度`...
在Java编程中,有时我们需要将输入的字符串进行倒序输出,这在各种场景下都有可能用到,例如处理用户输入、数据反转等。本篇文章总结了三种常用的Java实现字符串倒序输出的方法,以下是对这些方法的详细解释: 1. *...