提问人:pinkbird 提问时间:10/31/2022 更新时间:11/1/2022 访问量:599
查找序列中的第 n 项
Finding the nth term in a sequence
问:
我有一个序列,我正在尝试制作一个程序来查找序列的第 n 项。
顺序如下:
1, 11, 21, 1211, 111221, 312211...
在此序列中,每个术语描述前一个术语。例如,“1211”表示上一术语;前一项是“21”,其中出现一次 2,然后出现一次 1 (=1211)。要得到第三个项“21”,请看第二个项:11。有两次出现 1 给我们“21”。
import java.util.*;
class Main {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int n = scan.nextInt();
System.out.println( Main.num(n-1, "1"));
}
public static String num(int times, String x){
if(times == 0){
return x;
}else{
//System.out.println("meow");
String y = "" + x.charAt(0);
int counter = 0;
for(int i = 1; i < x.length(); i++){
if(x.charAt(i) == x.charAt(i-1)){
counter++;
}else{
y += "" + counter + x.charAt(i-1);
counter = 0;
}
}
return num(times--, y);
}
//return "";
}
}
我的代码使用递归来查找第 n 项。但是,它给我们带来了错误:(
首先,我通过向它传递项数 “num” 来开始方法 “num”(因为已经给出了第一项)和第一项 (1)。
在方法 num 中,我们首先使用条件来建立基本情况(当您找到第 n 项时)。
如果基本情况为 false,则在序列中找到下一项。
答:
这是一个非常酷的序列!我喜欢它是基于英语而不是数学的,哈哈。(虽然现在我想知道......有没有我们可以为第 n 项制定的公式?我很确定这是不可能的,或者使用一些疯狂的数学水平,但只是要考虑的事情......
在解决方案中,代码的递归逻辑是正确的:找到每个项后,使用已知数字重复该方法,并使用该元素查找下一个项,并在确定第一个元素后结束。您的基本情况也是正确的。n
但是,您开发的用于确定序列中的术语的算法是问题所在。
为了确定序列中的下一个元素,我们想要:
逻辑错误:
为下一个元素创建一个空变量 , 。但是,变量 不应从 开始。这是因为每个元素总是至少出现 ,所以我们应该初始化
y
counter
0
1
int counter = 1;
遍历 中的字符。(您正确地执行了此步骤)我们从 开始,因为我们将每个字符与前一个字符进行比较。
x
i = 1
如果当前字符等于前一个字符,则递增 。
counter
1
否则,我们将要重复的字符连接起来,以 .请记住,要重新初始化为 ,而不是 。
counter
y
counter
1
0
技术错误:
- 一旦我们到达迭代的末尾,我们需要将我们的 final 和 character 连接起来,因为 final 字符的 else 语句永远不会在我们的 for 循环中运行。
x
counter
y
这是通过以下代码完成的:y += "" + counter + x.charAt(x.length() - 1);
- 最后,当您进行递归调用时,您应该这样做,而不是 .这两个参数之间的区别在于,对于原始代码,您正在递减。这意味着在方法调用后,当我们希望将减少的值发送到方法中时,值会减小。为了解决这个问题,我们需要通过做 .
--times
times--
times
--times
import java.util.*;
class CoolSequence {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int n = scan.nextInt();
System.out.println(num(n, "1"));
}
public static String num(int times, String x){
if(times == 0){
return x;
}
else{
String y = "";
int counter = 1;
for(int i = 1; i < x.length(); i++){
if(x.charAt(i) == x.charAt(i - 1)){
counter++;
}
else{
y += "" + counter + x.charAt(i - 1);
counter = 1;
}
}
y += "" + counter + x.charAt(x.length() - 1);
return num(--times, y);
}
}
}
测试:
6
13112221
另一种方法是使用迭代方法:
import java.util.*;
class CoolSequence2 {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
ArrayList<String> nums = new ArrayList<String>();
int n = scan.nextInt();
String val = "1";
for(int i = 0; i < n; i++){
String copy = val;
val = "";
while(!copy.equals("")){
char curr = copy.charAt(0);
int ind = 0;
int cons = 0;
while(ind < copy.length() && curr == copy.charAt(ind)){
cons += 1;
ind += 1;
}
val += String.valueOf(cons) + copy.charAt(cons - 1);
copy = copy.substring(cons);
}
nums.add(val);
}
System.out.println(nums.get(nums.size() - 1));
}
}
6
13112221
在这种方法中,我们使用 for 循环来遍历术语。为了确定每个元素,我们执行与您的逻辑类似的方法:n
- 我们创建一个空字符串 ,用于保存新元素,并将当前元素存储在 中。我们还初始化一个 ,类似于 .
val
copy
cons
counter
- 虽然不为空,但我们遍历并递增,直到有一个元素不等于下一个元素。
copy
copy
cons
- 发生这种情况时,我们将重复的元素连接起来,就像在代码中一样。然后,我们从中剪掉重复的元素并继续该过程。
cons
val
copy
- 我们将 的新值 添加到 ,并不断遍历元素。
val
nums
n
我希望这两种解决您的问题的方法对您有所帮助!如果您有任何其他问题或澄清:)请告诉我
评论
您可以与反向引用一起使用。Pattern
正则表达式匹配任何单个字符 () 和同一字符 () 的零个或多个序列。 称为反向引用,它指的是括在括号 1st 中的字符串。"(.)\\1*"
"(.)"
"\\1*"
"\\1"
例如,它与 和 匹配。111
22
1
111221
replaceAll()
每次匹配时调用参数指定的 lambda 表达式。lambda 表达式接收 a 并返回一个字符串。匹配的字符串将替换为结果。MatchResult
在本例中,lambda 表达式将匹配字符串 () 和第一个字符 () 的长度连接起来。match.group().length()
match.group(1)
static final Pattern SEQUENCE_OF_SAME_CHARACTER = Pattern.compile("(.)\\1*");
static String num(int times, String x) {
for (int i = 0; i < times; ++i)
x = SEQUENCE_OF_SAME_CHARACTER.matcher(x).replaceAll(
match -> match.group().length() + match.group(1));
return x;
}
public static void main(String[] args) {
for (int i = 1; i <= 8; ++i)
System.out.print(num(i - 1, "1") + " ");
}
输出:
1 11 21 1211 111221 312211 13112221 1113213211
评论