-1

I want to check if any sequence of the elements of an array is repeating and be able to set the size of the sequence. For example:

var array = ["a", "b", "c", "d", "b", "c", "a"]

If you check for size = 1 (meaning if any single element is repeating) I should get true

If you check for size = 2 (meaning if any 2 elements are repeating ) I should get true (b,c sequence is repeating)

If you check for size = 3 I should get false

Thank you for your help. I am really stuck with this one

Paul Fitzgerald
  • 11,770
  • 4
  • 42
  • 54
perrosnk
  • 835
  • 2
  • 13
  • 23

3 Answers3

3

Another way of solving the task would be checking whether the hash (concatenated values) across sliding window of width N is seen more than once:

const src = ['a', 'b', 'c', 'd', 'b', 'c', 'a'],

      hasDupSeqOfSizeN = (arr, N, hashMap=[]) =>
        arr.some((_,i,__,hash=arr.slice(i,i+N).join('\ud8ff')) => 
          hashMap.includes(hash) || (hashMap.push(hash), false))
        
console.log(hasDupSeqOfSizeN(src,2))
.as-console-wrapper{min-height:100%;}
Yevhen Horbunkov
  • 14,965
  • 3
  • 20
  • 42
2

This might not be the most efficient answer, but it should get you what you're looking for

function checkSeq(arr, size) {
    for (var i = 0; i < arr.length; i++) {
      for (var j = i+1; j < arr.length; j++) {
        if (arr[i] === arr[j] && isValidSequence(arr, i, j, size)) {
          return true;
        }
      }
    }
    return false;
  }

function isValidSequence(arr, i, j, size) {
    for (var k = 1; k < size; k++) {
      if (j+k >= arr.size || arr[i+k] !== arr[j+k]) {
        return false;
      }
    }
    return true;
  }

I checked your 3 conditions and got the correct responses

checkSeq(array, 1) // true

checkSeq(array, 2) // true

checkSeq(array, 3) // false

rhavelka
  • 2,283
  • 3
  • 22
  • 36
2

Here is a solution that should work for array items that are not just characters:

const array = ["a", "b", "c", "d", "b", "c", "a", "a", "a", "b", "c"]

function checkSequence(sequence, size) {
    const matches = {}; // Stores counts of potential seqences, eg. { 'a,b': 1, 'b,c': 2 }

    for (let i = 0; i <= sequence.length - size; i++) {
        const current = sequence.slice(i, i + size); // get n items following each other starting at i
        // If match exists, increase count, else first match
        if (matches[current]) {
            ++matches[current];
        } else {
            matches[current] = 1;
        }
    }

    // Find first sequence that repeats and return true
    for (const seq in matches) {
        if (matches[seq] >= 2) {
            return true;
        }
    }

    return false;
}

console.log(checkSequence(array, 1));
console.log(checkSequence(array, 2));
console.log(checkSequence(array, 3));
console.log(checkSequence(array, 4));

matches is used to keep count of each processed sequence and is increased accordingly. The input array has been expanded to confirm that it works correctly.

The code can still be optimized by returning earlier, as soon as an existing match is found instead of looping through each of the matches at the end of the function.

Edit: Here is updated code that would check if the next match overlaps with the previous match. If there's an overlap, it does not consider it a match and continues with the search, else it will return true as soon as a match is found.

const array = ["a", "b", "c", "d", "e", "c", "d", "e", "c", "d"];

function checkSequence(sequence, size) {
  const matches = [];

  for (let i = 0; i <= sequence.length - size; i++) {
    // Assuming numbers or characters only
    const current = sequence.slice(i, i + size).join();

    // You'll need a different way to store/compare for other data types
    if (matches.find(match => match.value === current && i >= match.end)) {
      return true;
    } else {
      matches.push({ value: current, end: i + size });
    }
  }

  return false;
}

console.log(checkSequence(array, 1));
console.log(checkSequence(array, 2));
console.log(checkSequence(array, 3));
console.log(checkSequence(array, 4));
console.log(checkSequence(array, 5));
FrostyZombi3
  • 619
  • 5
  • 13
  • This example fails for e.g. `... array = ["b", "b"]` and `... checkSequence(array, 1)`. – Peter Seliger Jun 24 '20 at 08:02
  • If `array = ["b", "b"]` and size = 1 (sequence length), then your sequence would be "b", which is repeated, therefore it should return true. – FrostyZombi3 Jun 24 '20 at 08:34
  • 1
    I'm terribly sorry. I did encounter a copy paste error in my test environment. I will continue testing and as a consequence of that might upvote this A. of yours. – Peter Seliger Jun 24 '20 at 08:41
  • ... what is/was the expected result for `["a", "b", "c", "d", "e", "c", "d", "e", "c"]` and `console.log(checkSequence(array, 4));` and the expected result for `["a", "b", "c", "d", "e", "c", "d", "e", "c", "d"]` and `console.log(checkSequence(array, 4));` as well as `console.log(checkSequence(array, 5));` ? – Peter Seliger Jun 24 '20 at 08:55
  • I see, you got me there... the overlap in `["c", "d", "e", "c", "d", "e", "c"]` would cause a result of true for size = 4 and the same would apply for size = 5 – FrostyZombi3 Jun 24 '20 at 09:02
  • I'm not really sure myself. In the end both approaches , your's and the one of @rhavelka, handle tricky cases, like the ones from the comment above, alike. And I don't even think this is wrong. Actually the OP is responsible for coming up with the exact requirements. You will get the upvote anyhow. – Peter Seliger Jun 24 '20 at 09:04
  • @PeterSeliger : just in case your extensive testing includes performance benchmarks just as well, pay attention that above solution has [certain performance gaps](https://jsbench.me/1jkbtc5pno/1) – Yevhen Horbunkov Jun 24 '20 at 12:51
  • @PeterSeliger @FrostyZombi3 I am looking for a solution that would not return true for size = 4 in `["c", "d", "e", "c", "d", "e", "c"]` because the array `["d", "e", "c"]` is not an exact repetition of `["c", "d", "e", "c"]` – perrosnk Jun 25 '20 at 17:55
  • @perrosnk ... if it is about just handling characters/strings then go with *Yevgen Gorbunkov*'s approach. – Peter Seliger Jun 25 '20 at 19:55
  • @perrosnk since you did not specify, if your items need to be objects for example, you may need to remove the `join()`, but this will mean you'll need to compare the match arrays. You could `JSON.stringify()` and compare, loop though and compare elements, etc. – FrostyZombi3 Jun 25 '20 at 22:42
  • @FrostyZombi3 I picked Yevgen Gorbunkov's due to the fact that it seems faster for strings on the performance test. I really like your approach though, which seems very clean and with some minor changes will be able to handle other data types. thank you very much for that! – perrosnk Jun 28 '20 at 19:52