前几天朋友丢给我这么一道编码题,问我有没有什么想法,我当时第一想法是这道题是不是leetcode那种,这货不会是要在我这装逼炫耀吧,那就尴尬了,作为一个还没深入接触过leetcode的程序员(ps:实在惭愧),怎么可能短时间内把既准确又高效的代码甩给他,并当面给他重重一击呢。哈哈哈,开个玩笑,言归正传。
说起这种分割字符串的问题,我最先想到了学生时代接触到的游标概念,所谓游标,其实就是一个从某一端向另一端依次遍历的指针,所以我在想,用游标是不是可以作为这道题的一种解决策略呢。 基于以上想法,快速梳理一下,要达到目的必须注意以下几个关键点:
话不多说直接上代码(以下代码可能有的bug点:特殊字符、null指针等,目前均尚不考虑)。
public class SplitDemo {
public List<String> split(String str, String reg) {
List<String> result = new ArrayList<>();
Character[] strArr = toCharacterArray(str);
Character[] regArr = toCharacterArray(reg);
//游标逻辑
for (int i = 0; i < strArr.length; i++) {
//标识多字符是否完全匹配
boolean flag = false;
for (int j = 0; j < regArr.length; j++) {
flag = regArr[j].equals(strArr[i + j]);
if (!flag) {
break;
}
}
if (!flag) {
continue;
}
//特殊null值赋值
for (int j = 0; j < regArr.length; j++) {
strArr[i + j] = null;
}
}
//结果集封装
String item = "";
for (Character character : strArr) {
if (null != character) {
item = item + character;
} else {
if (!"".equals(item)) {
result.add(item);
item = "";
}
}
}
if (!"".equals(item)) {
result.add(item);
}
return result;
}
/**
将字符串转为字符包装类数组
*/
private Character[] toCharacterArray(String str) {
Character[] result = new Character[str.length()];
for (int i = 0; i < result.length; i++) {
result[i] = str.charAt(i);
}
return result;
}
}
复制代码
测试方法
public static void main(String[] args) {
List<String> result = new SplitDemo().split("asasdecdsdxa", "sd");
for (String str : result) {
System.out.println(str);
}
}
复制代码
输出结果
初步完成,但感觉有些繁琐,贴给朋友交流之后,有了另外的处理方法。直接上朋友的代码截图。
这段代码有几个主要的点:
整体逻辑非常清晰,而且代码量更少,初步判断效率更高,这里我不免对String类中的indexOf(String str, int fromIndex)方法充满了好奇,下面让我们追一下JDK源码(版本为JDK8)。
/**
* Returns the index within this string of the first occurrence of the
* specified substring, starting at the specified index.
*
* <p>The returned index is the smallest value <i>k</i> for which:
* <blockquote><pre>
* <i>k</i> >= fromIndex {@code &&} this.startsWith(str, <i>k</i>)
* </pre></blockquote>
* If no such value of <i>k</i> exists, then {@code -1} is returned.
*
* @param str the substring to search for.
* @param fromIndex the index from which to start the search.
* @return the index of the first occurrence of the specified substring,
* starting at the specified index,
* or {@code -1} if there is no such occurrence.
*/
public int indexOf(String str, int fromIndex) {
return indexOf(value, 0, value.length,
str.value, 0, str.value.length, fromIndex);
}
/**
* Code shared by String and StringBuffer to do searches. The
* source is the character array being searched, and the target
* is the string being searched for.
*
* @param source the characters being searched.
* @param sourceOffset offset of the source string.
* @param sourceCount count of the source string.
* @param target the characters being searched for.
* @param targetOffset offset of the target string.
* @param targetCount count of the target string.
* @param fromIndex the index to begin searching from.
*/
static int indexOf(char[] source, int sourceOffset, int sourceCount,
char[] target, int targetOffset, int targetCount,
int fromIndex) {
if (fromIndex >= sourceCount) {
return (targetCount == 0 ? sourceCount : -1);
}
if (fromIndex < 0) {
fromIndex = 0;
}
if (targetCount == 0) {
return fromIndex;
}
char first = target[targetOffset];
int max = sourceOffset + (sourceCount - targetCount);
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;
}
}
}
return -1;
}
复制代码
可以看到,其在内部调用了静态方法indexOf(char[] source, int sourceOffset, int sourceCount,char[] target, int targetOffset, int targetCount,int fromIndex),传入参数从左往右依次可以理解为源字符数组(标题中的第一个字符串),源字符数组偏移量(内部调用时默认传入0),源字符数组长度,要查找的字符数组(标题中的第二个字符串),要查找的字符数组偏移量(依旧是0),要查找的字符数组长度,以及初始匹配位置的下标。
进到方法内部,可以看到大体的流程是:
究其内部原理,实际上跟作者一开始的游标方案有异曲同工之处,但更为精妙,尤其是流程控制语句、临界值运用都非常精湛,值得学习!
以上就是本次分享的全部内容啦,有不对的地方欢迎同学们指正!