找到斐波那契单词序列的第 n 个单词 (Java)

如何解决找到斐波那契单词序列的第 n 个单词 (Java)

我正在尝试解决这个任务:

设 x[0] =0; x[1] =1; x[i] = x[i-2] + x[i-1]

找到单词 x[n] 的第 k 个字符,看它是 '0' 还是 '1',边界为 1

例如,对于序列 0110110101101,我们有

x[0] = 0

x[1] = 1

x[2] = 01

x[3] = 101

x[4] = 01101

x[5] = 10101101

当我使用 n = 44 及更高版本进行测试时,IDE 会抛出 OutOfMemoryError Java 堆空间。我知道我正在做的方式将存储序列的第 n 个单词、第 n-1 个单词和第 n-2 个单词,这会占用大量内存,但我想不出更好的方法

在对论文进行一些草稿工作后,我还看到要找到 n = 3 之后的第 n 个单词,while 循环只需要运行 n-2 次但没有运气实现

我还尝试将每个单词存储在 String ArrayList 中并使用递归进行,但效率更低

感谢任何提示

这是我的代码

import java.util.Scanner;
public class BinarySequence {
    public static void main(String[] args) {
        Scanner read = new Scanner(system.in);
        int t = read.nextInt(); //number of test to run
        while (t>0){
            String s0 = "0";
            String s1 = "1";
            int n = read.nextInt(); //nth fibonacci word
            int k = read.nextInt(); // kth char of the word
            System.out.println(fib(s0,s1,n-1).charat(k-1));
            t--;
        }
    }
    private static String fib(String s0,String s1,int n) {
        String ans ="";
        if(n==0)
            return s0;
        else if(n==1)
            return s1;
        else {
            while(n>=0){
                ans = s0+s1;
                s0=s1;
                s1=ans;
                n--;
            }
            return ans;
        }
    }
}

解决方法

输入 k 被限制在 192 之间,因此计算序列字符串只需要前 92 个字符。但是,对于每个不同的 x[i] 值,字符串的开头都会发生变化。对于前十一个¹ x[i] 值,字符串取决于x[i-1]x[i-2] 的完整值,但在第十一个x[i] 值之后/处{{1} 的第一个字符串} 已经足够长,x[i-2] 的值不再重要,因为它在结果的末尾连接。较大索引的 x[i-1]x[i-1] 值可以如下所示:

x[i-2]

假设 x[i-1] = 1111111...1111111 + xxxxxxxxxx x[i-2] = 2222222...2222222 + yyyyyyyyyy x[i] = 2222222...2222222 + yyyyyyyyyy + 1111111...1111111 + xxxxxxxxxx /111...111 部分(当然这些不是实际字符)是 92 个字符长,那么你不需要剩下的东西 222...222 和 {{ 1}} 之后,因为无论如何您都无法使用有限的 xxxxx... 值访问它们。所以对于你的问题,

yyyyy...

相同
k

足够高的x[i] = 2222222...2222222 + yyyyyyyyyy + 1111111...1111111 + xxxxxxxxxx

现在剩下的问题是计算/选择在计算 x[i] = 2222222...2222222 甚至 i 之类的东西时应该使用 111..111222...222 的哪个序列。最有可能的情况类似于奇数/偶数检查,您可以在其中编写如下内容:“当 x[24] 为偶数时,使用 x[80],否则使用 n。”。

¹) 检查是否存在逐一错误,92 个字符的阈值可能不在索引 x[10] 处。

,

有一个解决方案适用于任何 k,它是一个 int 并且不包含昂贵的串联操作,具有 O(1) 内存和 O(log(k)) 时间1.

前缀和奇偶校验

该算法使用@Progman 在他们的答案中所做的观察,即如果 a < bab 具有相同的 parity,则 x[a]x[b] 的前缀(根据 x[n-2]x[n] 的前缀这一事实得出结论)。这意味着我们不需要计算序列中的 n 项,我们只需要找到 j,我将其定义为最小数,使得 x[j] 的长度为大于 k,并且 jn 具有相同的奇偶校验。

例如,如果n = 12345k = 1,那么我们只需要计算最多x[3] = 101,因为我们知道x[3]x[12345]的前缀因为 312345 都是奇数。所以答案是0

进入O(1)记忆

用于避免存储零和一长序列的方法如下:

无需计算x

首先注意单词 x[n] 的长度等于 fib[n],其中 fib 是斐波那契数列。因此,该方法不是计算 x 中的字符串并索引到 x[n] 以查找是返回 1 还是 0,而是使用 x[n] = x[n-2] + x[n-1] 的事实。您可以通过将 x[n][k]x[n-2] 的长度(其中 x[n-1]k)。经过这个比较,就知道x[n-2] 是等于x[n-2] 还是fib[n-2]。然后我们重复这个过程,将 x[n][k] 适当地设置为 x[n-2][k]x[n-1][k-fib[n-2]],而 n 保持不变或适当地设置为 n-1。如此重复直到 n-2k,此时 k-fib[n-2] 将是 n == 0,所以 n == 1 要么等于 k 或 {{1} },根据定义。

无需存储0

计算中不需要

x[n][k],只需要x[0][0] = 0,这样可以避免存储很长的数字序列,但是我们肯定需要存储最多x[1][0] = 1的所有斐波那契数,以便执行上一段中定义的步骤?不我们没有!这是因为我们首先找到了 fib,只在内存中保留了 xfib。然后我们重新排列方程以找到 fib[j],并使用它来回溯斐波那契数列以找到 j

实施

现在我已经解释了算法,下面是一个 Java 实现:

首先我们定义一个 fib[i-1] 类来封装斐波那契数列,保持代码简洁。 (如果你需要坚持一个文件,你可以把它移到一个内部类。)

fib[i]

那么,实际算法:

fib[n-2] = fib[n] - fib[n-1]

x[n][k]或回家

Fib 时间复杂度意味着它运行得非常快,即使对于非常大的 class Fib { private long a = 0; private long b = 1; private int index = 0; void advance() { long sum = a + b; a = b; b = sum; index++; } void backtrack() { long diff = b - a; b = a; a = diff; index--; } long getPreviousValue() { return a; } long getCurrentValue() { return b; } int getIndex() { return index; } } 值也是如此。如果您希望 public class Main { public static int fibNK(int n,int k) { Fib fib = new Fib(); // if n is odd,go to the next fib so that fib.getIndex() is 1 // this ensures that n and fib.getIndex() are either both even or both odd if (n % 2 == 1) { fib.advance(); } // find the first fibonacci number greater than k that is still even/odd while (k >= fib.getCurrentValue()) { // x+2 is even if x is even,so advance twice fib.advance(); fib.advance(); } // now to find character k of the word: // if we're looking at the first or second fibonacci word,"0" or "1",// then the character at index k must be 0 or 1 while (fib.getIndex() > 1) { // only fib[i] and fib[i-1] are stored,but fib[i-2] is needed,so backtrack fib.backtrack(); // we are trying to find fibWord[i][k] // fibWord[i][k] = fibWord[i-2] + fibWord[i-1] // if k >= fibWord[i-2].length,then the target character is in the second part of the word,fibWord[i-1] if (k >= fib.getPreviousValue()) { // specifically,if k >= fib[i-2],then fibWord[i][k]==fibWord[i-1][k-fibWord[i-2].length] k -= fib.getPreviousValue(); } else { // otherwise,fibWord[i][k]==fibWord[i-2][k],so another backtrack is needed fib.backtrack(); } } // return either 0 or 1 return fib.getIndex(); } public static void main(String[] args) { // test the algorithm by using to print the first few words in `x`,one letter at a time Fib fib = new Fib(); for (int n = 0; n < 8; n++) { for (int k = 0; k < fib.getCurrentValue(); k++) { System.out.print(fibNK(n,k)); } System.out.println(); fib.advance(); } } } 的值大于 BigInteger(相当于 O(log(k)) 的值大于 k),您可以将 k 更改为 {{1 }} 但是这在计算斐波那契数时可能会导致溢出错误,因此您需要将一些变量更改为BigInteger,尽管这会略微增加时间和空间复杂度。


1 斐波那契数列有一个exponential lower bound,所以Integer.MAX_VALUE的长度大于n,也就是说45斐波那契数列需要计算以找到大于 k 的一个。然后第二阶段执行相同数量的“回溯”操作以返回到 longx[n],这是额外的 (3/2)**n 时间,总共产生 O(log(k))

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?