1

I have an array of numbers which can be a value of either 1 or 0. I need to create a function that detects if there is one instance where there is a consecutive 1 and no other 1 exist outside of that instance, returns true else false

So to sum it up here's a clearer view of the constraints to return true:

  1. must have only one set of consecutive 1
  2. there must be no other 1 outside of that one instance of consecutive 1

Test cases:

[0, 0, 1, 1, 0, 0] true

[1, 0, 1, 0, 0, 0] false

[1, 0, 1, 1, 0, 0] false

[1, 1, 0, 1, 1, 0] false

[0, 1, 1, 1, 1, 0] true

[0, 0, 1, 1, 1, 1] true
2
  • 1
    That's a fine problem statement. What is your intuition on how to solve it? Commented Nov 10, 2022 at 12:22
  • I'm thinking of reducing the array, check if it has found a 1, once it does, it will flag that it started to detect the 1. Once that flag is detected, it will continue to check for more 1s. If there are more than one 1 already and it has detected a 0 and has detected another 1, then it returns false, otherwise true. My problem is with that in mind [0, 0, 1, 1] would be incorrect since it hasn't detected a 0 yet. Commented Nov 10, 2022 at 12:29

2 Answers 2

3
function hasOneRun(arr) {
  let switches = 0;
  for (let i = 0; i < arr.length; i++) {
    switches += arr[i] ^ arr[i-1];
    if (switches > 2) return false;
  }
  return switches > 0;
}

Counts how many times it switches from 0 to 1 or 1 to 0. arr[i] ^ arr[i-1] is 1 only if the value changes from the previous value. If switches is 0 at the end, there were only 0s, so false. If it's greater than 2, then it switched to 1, then to 0, then back to 1, so there were too many runs.

Here's a fun one-liner :D

Math.ceil(arr.reduce((switches, val, i) => switches + (val ^ arr[i-1]))/2) === 1;

Edit: Some other ideas

const startOne = (el, i, arr) => el == 1 && arr[i-1] != 1;
const is1 = x => x === 1;

arr.filter(startOne).length == 1;
arr.findIndex(startOne) === arr.findLastIndex(startOne);
arr.slice(arr.findIndex(is1), arr.findLastIndex(is1)+1).every(is1)


/^0*1+0*$/.test(arr.join('')); // zero or more zeroes, one or more ones

Or if you treat it as a sequence of bits…

function hasOneRun(x) {
  while (!(x&1)) x >>= 1; // shift off trailing zeroes
  return (x&(x+1)) === 0; // see if one less than power of 2 (all 1s)
}
console.log(hasOneRun(0b001111000));
console.log(hasOneRun(0b11000));
console.log(hasOneRun(0b1111));
console.log(hasOneRun(0b1110000111000));
Sign up to request clarification or add additional context in comments.

6 Comments

for some reason this works, can you please expound what ^ does? I have no idea what it is
Exclusive or (xor). 0 ^ 0 == 0, 0 ^ 1 == 1, 1 ^ 0 == 1, 1 ^ 1 == 0. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
You could also write if (arr[i] != (arr[i-1] ?? 0)) ++switches;
thanks! that is so much easier to digest.
Your one-liner fails for the test cases [0, 0, 1, 1, 0, 0] and [0, 1, 1, 1, 1, 0]
|
1

You can also solve this by treating it as a string, and splitting it up where there are any sequences of zeroes:

const testCases = [
  [[0, 0, 1, 1, 0, 0], true],
  [[1, 0, 1, 0, 0, 0], false],
  [[1, 0, 1, 1, 0, 0], false],
  [[1, 1, 0, 1, 1, 0], false],
  [[0, 1, 1, 1, 1, 0], true],
  [[0, 0, 1, 1, 1, 1], true]
];
const f = a => a.join('').split(/0+/).filter(i=>i).length===1;
testCases.forEach(t=>console.log(f(t[0])===t[1] ? 'pass' : 'fail'));

3 Comments

sweet, this is also a nice way to solve the problem, thanks you are brilliant.
If it's a string, regex does nicely. /^0*1+0*$/.test(arr.join(''))
@TrevorDixon very nice!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.