0

I have a working solution for this Kata (find nth value of Fibonacci Sequence), however I keep getting a timeout error. Can anyone offer advice on how to refactor this to run more efficiently? Thanks in advance!

Here is the link with description - https://www.codewars.com/kata/simple-fun-number-395-fibonacci-digit-sequence/train/javascript

You are given three non negative integers a, b and n, and making an infinite sequence just like fibonacci sequence, use the following rules:

step1: use ab as the initial sequence. step2: calculate the sum of the last two digits of the sequence, and append it to the end of sequence. repeat step2 Your task is to complete function find. Return nth digit(0-based) of the sequence.

function find(a,b,n){
  let start = ("" + a + b);
  let next = a + b;
  let seq = start + next;
  
  while (seq.length <= n) {
    seq += (parseInt(seq[seq.length-2]) + parseInt(seq[seq.length-1]));
  }
  return parseInt(seq[n]);
}

console.log(find(7,8,9))

// should return 5
Justin Cefai
  • 141
  • 1
  • 3
  • 12
  • Here is the Codewars link - https://www.codewars.com/kata/simple-fun-number-395-fibonacci-digit-sequence/train/javascript – Justin Cefai Oct 17 '18 at 23:30
  • `function find(a,b,n) { return 5; }`? – Blue Oct 17 '18 at 23:36
  • Not sure about the speed, but your answer is only correct by coincidence. You need to `parseInt` each string individually. You code continually adds `15` to the end of the string. – Mark Oct 17 '18 at 23:40
  • @MarkMeyer You're absolutely right - code has been edited to reflect that change. However, I tried it before with parseInt on each string and logged each iteration to the console and while the output was correct, I was still receiving the timeout error. Any thoughts? – Justin Cefai Oct 17 '18 at 23:57
  • 1
    Please add a description of the problem to the question, not just a link in the comments. – Barmar Oct 18 '18 at 00:02
  • @Barmar Done, thanks! – Justin Cefai Oct 18 '18 at 00:05
  • @JustinCefai: You've misunderstood Barmar's comment. (S)he's not saying to add the *link*, (s)he's saying to add the *description*. Your question should continue to make sense long after codewars.com has disappeared or become infested with malware. – ruakh Oct 18 '18 at 00:08

2 Answers2

2

Firstly . . . don't use strings, don't use parseInt, don't hold onto the entire sequence at once. You only need numbers, and you only need the last two digits. Given a number x between 10 and 18 (which is the largest possible sum of two digits), its tens' place is 1 and its ones' place is x - 10. That alone will be a significant improvement.

Secondly . . . since the entire sequence after a given point is determined by the first two digits at that point,1 and there are only 100 possible sequences of two digits, every sequence has to repeat within 200 digits; that is, within at most 200 digits, it will necessarily enter a loop of repeating digits that it never gets out of, where that loop is less than 200 digits long.2 So if n is greater than a few hundred, you can massively optimize by finding the length of this loop and "skipping" a large multiple of that length.

1. Actually, this isn't quite true as written. For example, the sequences 69156… and 79167… bot contain 91, but followed by different things. This is because the '1' belongs to a two-digit number, both of whose digits are determined by the previous two digits. I'm not sure how to express this better, but hopefully you see what I mean. It doesn't affect the overall argument, but it's something you need to be careful with in how you apply the idea.
2. Actually much less; testing all possible values of a and b, I find that the sequence always enters the loop and completes its first iteration within just 25 digits! But I'm not sure how to rigorously justify this much smaller figure other than exhaustive testing; so it would probably be cheating to write the code in a way that relied on it.

ruakh
  • 175,680
  • 26
  • 273
  • 307
  • thanks for the response! In regards to "don't hold on to the entire sequence at once" - how would you find an element at the nth position if you're not keeping track of the length? – Justin Cefai Oct 18 '18 at 00:08
  • @JustinCefai: One option is to keep a `position` variable, and you're done when `position` reaches `n`. Another option is to decrease `n` as you progress through the sequence, and you're done when `n` reaches `0`. (N.B. in both cases, you need to be careful to handle two-digit numbers correctly.) – ruakh Oct 18 '18 at 00:10
  • I'm not quite sure how you get the tens place with `(x - x % 10) / 10` I think that gives you the number truncated to it's tens digit and one more `% 10` is required. – Mark Oct 18 '18 at 00:11
  • @MarkMeyer: Since it's a two-digit number, there's literally no difference between "the tens place" and "the number truncated to it's tens digit". An extra `% 10` is harmless but unnecessary. – ruakh Oct 18 '18 at 00:12
1

When you are converting and doing string operation it is generally slower.

function nextVal(num){
    const last = (num%10);
    const lastButOne = (num - last)/10 % 10;
    const sum = last + lastButOne;
    return sum < 10 ? num * 10 + sum : num *100 + sum;
}
function find(a,b,n){
  let num = a * 10 + b;
  const above = Math.pow(10, n);// anything less than we don't have enough digits


  while (num < above) {
    num = nextVal(num);
  }
  return Number(`${num}`.charAt(n));
}

The above code relies on number checking and only converts it into string (which can also be avoided)

Neo
  • 4,550
  • 6
  • 34
  • 51