【问题标题】:Detect nth term of binary sequence检测二进制序列的第 n 项
【发布时间】:2015-10-30 18:56:25
【问题描述】:

我有一个遵循特定逻辑的二进制序列,使得 它以0

开头

nth term = (n-1)th term 的序列 + 0 + inverse(reverse(n-1)th term)

例如:

0
0 + 0 + 1
001 + 0 + 011
0010011 + 0 + 0011011

这里,我需要找出第k个序列的第n项。

我的看法:

我写了一个递归函数来计算第 k 个序列中的项数

  public static long noOfElements(long elements){
     long answer;
     if(elements == 1)
        return 1;
     else
     answer = 1 + 2*noOfElements(elements-1);
     return answer;
}

经过分析,我发现序列遵循一定的规律,第k个序列可以对半分解,并切换0和1的值,我可以跟踪结果。

所以,我下面的函数将给定的序列递归地分解为 [0,0,1]

public static long letsBegin(long reqd, long length){
    long mid = (length + 1)/2;
    if(length <= 3){
        return reqd;
    }else{
        if(reqd > mid){
            reqd = reqd - 2*(reqd-mid);
            switcher();                 //Switcher stores if the value is switched
            return letsBegin(reqd, mid);
        }else{
            return letsBegin(reqd, mid);
        }
    }
}

最后,我在 [0,0,1] 中有索引 1、2 或 3,并相应地输出值。 这里的问题是

  1. 由于某些未知情况而失败(可能是我的逻辑错误)。
  2. 序列数最多可达到 50 个,使得元素数 = 1125899906842623,因此输出值需要很长时间(>2 秒) 可能出了什么问题?我的逻辑不正确吗

【问题讨论】:

    标签: java algorithm


    【解决方案1】:

    用递归很简单,第k个序列的元素个数是2^(k+1)-1:

    static int foo(long n, int k) { //n-th element (indexed from 0) in k-th sequence
        long length = (2L << k) - 1; // computes 2^(k+1)-1
        if(n >= length) return -1; // prevent invalid inputs
        if(n == length/2) return 0; // middle point
        if(n < length/2) return foo(n, k-1); //left half
        return 1 - foo(length - n - 1, k-1); //right half
    }
    

    在最后一次递归调用中,你同时翻转数组和返回值。

    编辑:

    请务必使用(2L &lt;&lt; k) 而不是(2 &lt;&lt; k),否则会导致溢出并可能导致无限递归。

    【讨论】:

    • 递归导致大型输入的堆栈溢出:-/
    • @Rockstar 怎么来的?您说您将拥有最多 50 个序列。请注意,在 63 个序列中,该位置不再适合 long,您需要使用 BigInteger 或其他东西来表示该位置。此外,此方法在堆栈上分配的空间很小,您至少需要在普通计算机上进行数千次递归调用才能导致任何问题。
    • 是的,最多50个序列,没有。元素 1125899906842623 ,对于输入 k = 50,n=1125899906842622 程序崩溃,堆栈溢出 if(n &lt; length/2) return foo(n, k-1);
    • 我的失败,(2 &lt;&lt; k) 导致整数溢出,我会在一分钟内编辑答案,
    • 谢谢,已修复。但现在它失败了 Exceeding time limit >2sec :-/
    【解决方案2】:

    您缺少一个案例(当 reqd == mid 时)并以不正确的长度调用递归函数(mid 而不是 mid-1)。在这些修复之后,函数看起来像这样:

    public static long letsBegin(long reqd, long length){
        long mid = (length + 1)/2;
        if(length <= 3){
            return reqd;
        } else{
            if(reqd > mid){
                reqd = reqd - 2*(reqd-mid);
                switcher();     //Switcher stores if the value is switched
                return letsBegin(reqd, mid-1);
            } else if(reqd < mid) {
                return letsBegin(reqd, mid-1);
            } else {
                return 0;
            }
        }
    }
    

    此外,代码比必要的复杂。尝试使用以下递归关系:

    T(n, k) = T(n, k-1)            if n < 2^{k-1}
            = 0                    if n = 2^{k-1}
            = 1 - T(2^k-n, k-1)    otherwise
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-10-20
      • 1970-01-01
      • 2021-02-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多