由于这似乎是一个家庭作业类型的问题,我将尝试先引导您朝着正确的方向前进,然后再提供解决方案。 我强烈建议您在查看我的解决方案(一旦我发布后)之前,先尽自己最大的能力自行解决问题,并在继续之前阅读this page
首先,考虑您可以接收的输入类型。由于您没有指定任何限制,因此您可以获得以下内容:
- “”(空字符串)
- “\n”(空格)
- “x”(单个字符)
- “xx”(两个字符串)
- “abc”(长度正确的字符串,但不包含您的子字符串)
- “.xyz”(要忽略的子字符串)
我可以继续说下去,但我相信你可以想出所有你可能收到的奇怪东西的各种组合。这些只是帮助您入门的几个示例(以及我已经在 cmets 中发布的示例)
接下来,想想你需要你的算法做什么。正如我在 cmets 中所说,听起来您想计算子字符串“xyz”的出现次数,而忽略子字符串“.xyz”的出现次数。现在考虑您将如何查找这些子字符串 - 您将在字符串中一次从左到右推进一个字符,以寻找与这两种可能性之一匹配的子字符串。当您找到其中之一时,您要么忽略它,要么数数它。
希望这会有所帮助,正如我所说,稍后我会在您有时间处理代码后发布解决方案。如果您确实解决了它,请继续发布您的解决方案(也许编辑您的问题以添加新代码或添加答案)最后我再次强烈建议您阅读this page如果您还没有。
编辑#1:
我想添加更多信息,那就是:您已经非常清楚此时需要做什么才能计算您的“xyz”子字符串 - 尽管输入逻辑存在小缺陷像“xaz”,很容易修复。您需要关注的是如何忽略子字符串“.xyz”,因此请考虑如何实现忽略逻辑,忽略它意味着什么?一旦你回答它应该开始为你聚集在一起。
编辑 #2:
您将在下面找到我对问题的解决方案。再次重要的是要了解解决方案的工作原理,而不仅仅是复制和粘贴它。如果您只是在不理解我的代码的情况下复制它,那么您就是在欺骗您自己想要获得的教育。目前我没有时间详细描述此代码为何以及如何工作,但我确实计划稍后再次编辑以添加这些详细信息。
import java.util.Scanner;
public class Main {
private static Scanner scan = new Scanner(System.in);
public static void main(String[] args) {
System.out.println("Give me a String:");
String s1 = scan.nextLine();
System.out.println(countSubstrings(s1));
}
public static int countSubstrings(String s1){
int index = 0;
int count = 0;
while (index < s1.length()-2) {
if(s1.charAt(index) == '.' && s1.charAt(index+1) != '.'){
index++;
}
else if (index+2 < s1.length() && s1.charAt(index) == 'x' && s1.charAt(index + 1) == 'y'
&& s1.charAt(index + 2) == 'z') {
count++;
index+=2;
}
index++;
}
return count;
}
}
编辑#3:
以下是上述代码为何如此运作的具体细节。首先,我们考虑这样一个事实,即我们正在数组中以特定顺序查找 3 个项目(一个三元组),如果我们在三元组的第一个项目之前看到第四个项目(一个句点),那么我们需要忽略三重奏。
根据我之前的编辑,我们需要定义忽略的含义。在这种情况下,我们的意思是根本不计算它,然后继续搜索要计算的有效子字符串。最简单的方法是在不增加count 的情况下推进index。
所以,问自己以下问题:
-
我的循环应该何时停止?因为我们正在寻找三元组,所以我们知道如果输入字符串的长度小于 3 或者当我们尚未检查的字符串中剩下的字符少于 3 个时,我们可以停止。例如,如果当我们到达索引 3 时输入是“xyzab”,我们知道不可能形成一个三元组,其中“a”是三元组中的第一个字符,因此我们的计数已经完成。
是否曾经我不想在一段时间后跳过接下来的 3 个字符?毕竟目标是寻找三元组,所以我不想跳过 3 个字符而不仅仅是 1 个字符吗?是的,有时您确实 不 想要跳过 3 个字符,那时您有类似“.axyz”的内容,因为有效的三元组可以在第二个字符超过句点时开始。所以实际上你只想跳过 1 个字符。
这一点,以及 index 在循环结束时总是加 1 的事实(稍后会详细介绍),这就是为什么 while 内的第一个条件仅将 index 提前 1:
if(s1.charAt(index) == '.' && s1.charAt(index+1) != '.'){
index++;
}
- 是否曾经我会看到一个句号并且不想忽略(跳过)下一个字符?是的,当下一个字符是另一个句点时,因为它可能表明需要跳过另一个三元组。考虑输入“..xyz”,如果您遇到第一个句点并跳过第二个句点,这将导致错误答案,因为您的算法可以将接下来的三个字符视为有效的三元组,但实际上由于第二个句点它是无效的.
这就是上述条件后半部分存在的原因:
`&& s1.charAt(index+1) != '.'`
每当您在循环内使用索引 +1 或索引 +2 等计算时,该循环会增加索引直到达到边界,您必须考虑计算超出边界的可能性,因为您不能依赖在循环上为您检查这一点,因为循环在循环结束或开始之前不会执行该检查(取决于它是哪种循环)
- 考虑到上述情况,您必须问自己:当我使用这些 index+1、index+2 等类型的计算时,如何防止超出边界的情况?答案是在您的条件中添加另一部分:
index+2 < s1.length()
您可能想知道 - 为什么不添加两个检查,因为我们使用的是 index+1 和 index+2?在这种情况下,我们只需要检查一下我们使用的最大索引是否会超出边界。如果 index +2 超出范围,我们不关心 index+1 是否存在,因为这无关紧要,我们不可能有匹配的子字符串。
- 接下来,在
while 内的第二个 if 内,您会看到将索引增加 2 的代码:index+=2; 这是为了提高效率,因为一旦我们确定了三元组,我们就知道没有办法用已经属于另一个三元组的字符组成另一个三元组。因此,我们想跳过它们,就像第一个要点一样,我们利用循环递增索引,所以我们只需要递增 2,然后让循环添加额外的 1。
最后我们到达循环内逻辑的结尾。这部分您已经很熟悉了,这就是index++;,它只是增加了我们当前正在检查的字符串中的位置。请注意,这与第一个要点协同工作。以“.axyz”的第一个要点为例。索引 0 中有一个句点,索引 1 中的字符不是另一个句点,因此第一个项目符号点的逻辑会将索引增加 1,使其为 1。在循环结束时,索引再次增加,使其为 2,从而跳过在此期间 - 在下一个循环开始时索引为 2,在循环开始时它从不是 1。
嗯,我希望这有助于解释它是如何工作的,并说明如何思考这些问题。基本原则是可视化当前元素的位置以及如何使用它来实现目标。同时考虑程序的不同元素具有什么样的属性以及如何利用它们 - 例如,一旦识别出三元组,就可以安全地跳过这些字符,因为它们具有只能使用一次。与任何程序一样,您总是希望尝试创建尽可能多的测试输入,以测试可能发生的所有奇怪的边界情况,以确保代码的正确性。我知道您可能不熟悉JUnit,但它是一个非常有用的工具,您可以在空闲时间尝试研究使用它的基础知识,而且如果您使用Eclipse IDE,它有您可以使用的集成 JUnit 功能。