Home > Software design >  Frequency of character B in Fibonacci string and time limit exceed error
Frequency of character B in Fibonacci string and time limit exceed error

Time:09-27

Consider the character string generated by the following rule:

  • F[0] = "A"
  • F[1] = "B"
  • ...
  • F[n] = F[n-1] F[n-2] with n > 1

Given two positive integers n and k. Let's count the number of characters 'B' in the first k positions of string F[n].

I came up with this idea and got time limit exceeded error:

public class Solution {
    public static long[] F = new long[50];
    public static Scanner input = new Scanner(System.in);

    public static long count(int n, long k) {
        if (n == 0 || k == 0) return 0;
        else if (n == 1) return 1;
        else {
            if (k > F[n - 1]) return count(n - 1, F[n - 1])   count(n - 2, k - F[n - 1]);
            else return count(n - 1, k);
        }
    }

    public static void main(String[] args) {
        F[0] = 1; F[1] = 1;
        for (int i = 2; i < 46; i  ) F[i] = F[i - 2]   F[i - 1];
        int T = input.nextInt();
        while (T-- > 0) {
            int n = input.nextInt();
            long k = input.nextLong();
            System.out.println(count(n, k));
        }
    }
}

Can some one help me to improve time complexity? Seems my solution has O(n^2) time complexity.

Test case for this question:

Input Output
4
0 1 0
1 1 1
3 2 1
7 7 4

CodePudding user response:

There seems to be a pattern related to Fibonacci numbers:

A
B
AB 1   1 (A count   B count)
BAB 1   2
ABBAB 2   3
BABABBAB 3   5
ABBABBABABBAB 5   8
      ^ k = 7
     BABABBAB 3   5
      ^ k = 2 (result = 3)
     BAB 1   2
      ^ k = 2 (result = 4)
     AB 1   1
     ^ k = 1 = A (result = 4)

Let g(l, r, k) represent the count of Bs in the first k positions of Fib[n] = l r. Then:

g(l, r, k):
  if (1, 1) == (l, r):
    return 1 if k == 2 else 0
  if (1, 2) == (l, r):
    return 1 if k < 3 else 2
  ll, rl = getFibSummands(l)
  lr, rr = getFibSummands(r)
  if k > l:
    return rl   g(lr, rr, k - l)
  return g(ll, rl, k)

This answer above may have misinterpreted the starting order of concatenation, which possibly should be BA, in which case, we would need to reverse l, r.

A
B
BA 1   1 (B count   A count)
BAB 2   1 
BABBA 3   2
BABBABAB 5   3
BABBABABBABBA 8   5
      ^ k = 7
BABBABAB
      ^ k = 7
     BAB
      ^ k = 2 (result = 3)
     BA
      ^ k = 2
      A
      ^ k = 1 (result = 4)
g(l, r, k):
  if (1, 1) == (l, r):
    return 1 if k == 2 else 0
  if (2, 1) == (l, r):
    return 1 if k < 3 else 2
  ll, rl = getFibSummands(l)
  lr, rr = getFibSummands(r)
  if k > l:
    return ll   g(lr, rr, k - l)
  return g(ll, rl, k)

CodePudding user response:

For clarity, define Fib(n) to be the Fibonacci sequence where Fib(0) = Fib(1) = 1, and Fib(n 2) = Fib(n 1) Fib(n).

Note that F[n] has Fib(n) characters, with Fib(n-1) of them being Bs.

Let C(n, k) be the number of B's in the first k characters of F[n].

The base cases are obvious

C(0, k) = 0
C(n, k) = 0 if k<=0
C(1, 1) = 1
C(2, k) = 1

In general:

C(n, k) = C(n-1, k)                         if k <= Fib(n-1)
        = Fib(n-2)   C(n-1, k - Fib(n-1))   otherwise

This is the observation that F[n] = F[n-1] F[n-2] and k lies in either the first part or the second. The first part has Fib(n-1) characters of which Fib(n-2) of them are B's.

If you precompute the Fibonacci numbers from 0 to n, then you can compute C(n, k) in O(n) arithmetic operations.

You tagged java, but here's a python solution including test cases:

def C(n, k):
    if n == 0: return 0
    total = 0
    fib = [1, 1]
    while len(fib) <= n and fib[-1] <= k:
        fib.append(fib[-1]   fib[-2])
    n = min(n, len(fib) - 1)
    while True:
        if n <= 2:
            return total   1
        elif k <= fib[n-1]:
            n -= 1
        else:
            total  = fib[n-2]
            k -= fib[n-1]
            n -= 1

tcs = [
    ([0, 1], 0),
    ([1, 1], 1),
    ([3, 2], 1),
    ([7, 7], 4)
]

for (n, k), want in tcs:
    got = C(n, k)
    if got != want:
        print('C(%d, %d) = %d, want %d' % (n, k, got, want))

This includes an optimization which reduces n so that initially k > Fib(n-1). This makes the code O(min(n, log(k))) arithmetic operations.

  • Related