查找序列中的第 n 项

Finding the nth term in a sequence

提问人:pinkbird 提问时间:10/31/2022 更新时间:11/1/2022 访问量:599

问:

我有一个序列,我正在尝试制作一个程序来查找序列的第 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,则在序列中找到下一项。

Java 递归 序列

评论


答:

5赞 Aniketh Malyala 10/31/2022 #1

这是一个非常酷的序列!我喜欢它是基于英语而不是数学的,哈哈。(虽然现在我想知道......有没有我们可以为第 n 项制定的公式?我很确定这是不可能的,或者使用一些疯狂的数学水平,但只是要考虑的事情......

在解决方案中,代码的递归逻辑是正确的:找到每个项后,使用已知数字重复该方法,并使用该元素查找下一个项,并在确定第一个元素后结束。您的基本情况也是正确的。n

但是,您开发的用于确定序列中的术语的算法是问题所在。

为了确定序列中的下一个元素,我们想要:

逻辑错误:

  1. 为下一个元素创建一个空变量 , 。但是,变量 不应从 开始。这是因为每个元素总是至少出现 ,所以我们应该初始化ycounter01int counter = 1;

  2. 遍历 中的字符。(您正确地执行了此步骤)我们从 开始,因为我们将每个字符与前一个字符进行比较。xi = 1

  3. 如果当前字符等于前一个字符,则递增 。counter1

  4. 否则,我们将要重复的字符连接起来,以 .请记住,要重新初始化为 ,而不是 。counterycounter10

技术错误:

  1. 一旦我们到达迭代的末尾,我们需要将我们的 final 和 character 连接起来,因为 final 字符的 else 语句永远不会在我们的 for 循环中运行。xcountery

这是通过以下代码完成的:y += "" + counter + x.charAt(x.length() - 1);

  1. 最后,当您进行递归调用时,您应该这样做,而不是 .这两个参数之间的区别在于,对于原始代码,您正在递减。这意味着在方法调用后,当我们希望将减少的值发送到方法中时,值会减小。为了解决这个问题,我们需要通过做 .--timestimes--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

  1. 我们创建一个空字符串 ,用于保存新元素,并将当前元素存储在 中。我们还初始化一个 ,类似于 .valcopyconscounter
  2. 虽然不为空,但我们遍历并递增,直到有一个元素不等于下一个元素。copycopycons
  3. 发生这种情况时,我们将重复的元素连接起来,就像在代码中一样。然后,我们从中剪掉重复的元素并继续该过程。consvalcopy
  4. 我们将 的新值 添加到 ,并不断遍历元素。valnumsn

我希望这两种解决您的问题的方法对您有所帮助!如果您有任何其他问题或澄清:)请告诉我

评论

1赞 Aniketh Malyala 10/31/2022
@pinkbird 一般来说,递归解决方案会更慢,但对于你的解决方案,你的递归基本上与 O(n) 循环相同。但是,我相信在这种情况下,您开始使用的递归方法实际上更快。我编码的迭代方法有更多的嵌套循环。不过,这两种方法都很好用:)希望这对您有所帮助!
3赞 user17233545 10/31/2022 #2

您可以与反向引用一起使用。Pattern

正则表达式匹配任何单个字符 () 和同一字符 () 的零个或多个序列。 称为反向引用,它指的是括在括号 1st 中的字符串。"(.)\\1*""(.)""\\1*""\\1"

例如,它与 和 匹配。111221111221

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

评论

1赞 Aniketh Malyala 10/31/2022
哇,我什至不知道那个方法的存在......非常酷和简化的解决方案:)
0赞 pinkbird 10/31/2022
这是SM更短!!WOWWW 谢谢 一个简单的问题,这是什么意思:静态最终模式SEQUENCE_OF_SAME_CHARACTER = Pattern.compile(“(.)\\1*"); ?