统计某个字符在字符串中的所在位置的集合
针对的这样的问题,我一开始手足无措,为什么这么说呢?因为基础不是很牢固,于是,翻看think in java这本书,才发现这本书是真的好,基础讲解的特别棒。闲谈少叙,言归正传,既然是判定字符所在字符串的位置的集合,我们列出流程图:
- 我们需要判断字符串是否为null或者为空,或者字符串的长度为0
- 我们首先生命一个数组,用来存放相同字符所在的位置,初始大小为5,size为下标
- 使用for遍历字符串,再使用String的charAt(int index)方法得到当前的char字符,和所给的字符进行判断
- 当两者相等时,首先判断数组的长度是否小于size,如果小于size则进行数组扩容;新数组的大小是就数组的长度左移1位再加上2,然后复制旧数组的数据。
- 如果数组的长度大于等于size,就字符所在的位置存储到数组当中。
- 因为我们在第四步进行了数组扩容,此时还要复制新数组,长度的为size的大小,除去新数组的冗余数据
我们分析好了之后,然后进行代码的的编写:
public static void main(String[] args) {
String s2 = "ddddddddddfddd";
int[] letter = countletterlocation(s2, 'd');
for (int i : letter) {
System.out.print(i + ",");
}
}
/**
* 字符串不为空
*
* @param params
* @return
*/
public static boolean isEmpty(String params) {
return params == null ? true : false;
}
/**
* 统计某个字符所在位置的集合
*
* @param s
* @param c
* @return
*/
public static int[] countletterlocation(String s, char c) {
int[] count = new int[5];
if (isEmpty(s)) return count;
int size = 0;
for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) == c) {
if (count.length - 1 < size) {
int newArrayLength = (count.length << 1) + 2;
count = Arrays.copyOf(count, newArrayLength);
}else{
count[size++] = i;
}
}
}
return Arrays.copyOfRange(count, 0, size);
}
output:0,1,2,3,4,6,7,8,9,11,12,13,
在字符串中下标为5的字符也是d,但没有存放到数组当中,这是为什么呢?原来,我们忽略了一个问题,就是当 if 的生命周期结束之后,就退回到循环的开头,不进入到else判断体中。当i=5正是临界条件,此时进入到if语句当中,而if语句只进行了数组扩容,并没有将i=5放进新数组中。当执行到 if 的右花括号,if的生命周期结束,退回到for的这条语句。当i=6时,跳过判断if的条件,条件不成立,进入到else的判断体中。前后都没有处理临界值,因而,我们需要处理临界值。
这时就会有5这个临界值的输出结果,但这样的代码并不符合代码整洁之道的要求,因为,我们可以这样想,不论旧数组需不需要扩容,都进行 count[size++] = i;的计算,这样就能避免代码的冗余。我们不仅仅要写出代码,还要写出良好的代码。因而,我们可以这样修改:
/**
* 统计某个字符所在位置的集合
*
* @param s
* @param c
* @return
*/
public static int[] countletterlocation(String s, char c) {
int[] count = new int[5];
if (isEmpty(s)) return count;
int size = 0;
for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) == c) {
if (count.length - 1 < size) {
int newArrayLength = (count.length << 1) + 2;
count = Arrays.copyOf(count, newArrayLength);
}
count[size++] = i;
}
}
return Arrays.copyOfRange(count, 0, size);
}
统计字符串中是否包含其他字符串的个数
对于这个问题,我们该如何思考呢?以下图为例子
- 首先判断源字符串和目标字符串不能为空。
- 假设都不为空,遍历源字符串,如果当前字符和目标字符串的首字母一样,我们再以源字符串的当前下标为起始下标,以目标字符串的长度加上当前下标为长度。比如下面代码中的内层循环for (int j = i; j < (i + decStr.length()); j++),意思是在从源字符串的当前下标到目标字符串的这个范围内再次遍历,如果i=1,此时变为for (int j =1; j < (1 + 2); j++)。其实内部循环还是遍历源字符串,只不过长度为当前下标的长度加上目标字符串的长度而已。
- 同时,声明一个临时变量,变量的初始值为目标字符串的0下标,如果源字符串的第j个字符等于目标字符串的第index字符,那么就继续遍历,直到index = 目标字符串的长度,此时,count++,通过if语句跳出内循环。
- 否则,使用break跳出内循环,退回到外循环当中。
-
但是这样的代码并不好看,我们可以简化代码:
测试结果:
public static void main(String[] args) {
String srcStr = "典型情况二进制安装的目录为/usr/local/mysql/data或源代码安装的目录为/usr/local/var。请注意这是配置时指定的数据目录的位置,而不是 mysqld启动时用--datadir指定的。运行时使用--datadir对寻找选项文件的服务器没有效果,因为服务器在处理命令行参量之前寻找这些选项。";
String decStr = "/usr/local";
System.out.println(countString(srcStr, decStr));
}
/**
* 判断一段文字当中,是否包含某段文字,及这段文字出现了几次
*
* @param srcStr 原文字
* @param decStr 比较文字
* @return count 次数
*/
public static int countString(String srcStr, String decStr) {
// 出现的次数
int count = 0;
if (isBlank(srcStr) || isBlank(decStr)) return count;
if (srcStr.length() < decStr.length()) return count;
for (int i = 0; i < srcStr.length(); i++) {
if (srcStr.charAt(i) == decStr.charAt(0)) {
int index = 0;
for (int j = i; j < (i + decStr.length()); j++) {
if (srcStr.charAt(j) != decStr.charAt(index++))
break;
if (index == decStr.length())
count++; //if本身就有跳出内循环的功能
}
}
}
return count;
}
- 一般的continue会退回到最内层循环的开头(顶部),并继续执行
- 一般的break会中断并跳出当前循环
- 如果多层循环的话,我们可以条件,使用break结束内部循环,并退回到紧接着内部循环的外部循环的顶部。