How do I find a maximum number of consecutive non-zero values in the array?

please format code with </> button * homework policy * asking questions

I am going to write a function that accept an array of integers(the frequency of number). In this function, I need to return a maximum number of consecutive non-zero values in the array. How am I going to do?

Hi @batmm ,

First of all you need to break the problem into small pieces :

  • How do you represent the fact that a number is non-zero?

  • What does consecutive mean in an array?

  • If you have to work with arrays, what programming structure are you going to use?

Also you can start to write the type signature of your function :

/**
 * Return the maximum number of consecutive non-zero values in the array 
 */
int maximumConsecutiveNonZero(int[] array) {
  return 0;
}

You can also write the rules down on paper and also make some drawings to try to approach it by hand :wink:

2 Likes

It is important to consider edge cases.

  • Is the array guaranteed to contain at least one element? If it can be empty, be sure that this will not cause your function to fail.
  • Also make sure that the function can handle an array that contains only zeroes.
1 Like

I tried to do the following, but in some situations it only return the first consecutive non-zero value but not the longest one. What might be the problem?

int maximumConsecutiveZero(int[] array) {
  int count = 0; 
  int maximum = 0; 
  for (int i=0; i<array.length; i++) { 
    if (array[i] != 0) { 
      count++;
    } else  { 
      if (count > maximum) { 
        maximum = count; 
      } 
      count = 0;
    }
  }
  return maximum;
}
1 Like

What happens if the longest sequence of non-zero values occurs right up to the end of the array? Does the appropriate variable get updated?

Im sorry, still not that clear. But my idea is to use if -else ?

1 Like

Yes, that idea is good.

As a test, try this with the function written as you posted it above:

void setup() {
  noLoop();
  int[] nums = {0, 1, 1, 0, 0, 1, 1, 1, 1};
  print(maximumConsecutiveZero(nums));
}

It should produce the following output:

4

However, it produces this instead:

2

Why is that? Could you fix the problem by moving this conditional block to somewhere else?:

      if (count > maximum) { 
        maximum = count; 
      } 
1 Like

This is my attempt on that: :innocent:

/**
 * Max Number of Consecutive Non-Zero Values (v1.0.1)
 * GoToLoop (2021/Apr/08)
 *
 * https://Discourse.Processing.org/t/
 * how-do-i-find-a-maximum-number-of-
 * consecutive-non-zero-values-in-the-array/29200/8
 */

final int[] vals = {
  0, // 0
  MAX_INT, MIN_INT, 0, // 2
  -1, 3, 40, 100, 0, // 4
  5 // 1
};

void setup() {
  println(str(vals));
  println(maxSeqNonZero(vals)); // 4
  exit();
}

@SafeVarargs static final int maxSeqNonZero(final int... arr) {
  if (arr == null || arr.length == 0)  return 0;

  int seqCount = 0, maxCount = 0;

  for (final int n : arr)
    maxCount = max(maxCount, seqCount += n != 0? 1 : -seqCount);

  return maxCount;
}
2 Likes

Your code passes all these tests, @GoToLoop:

  • final int[] values = {}; // empty array
  • final int[] values = {0}; // one zero value
  • final int[] values = {0, 0, 0}; // several zero values
  • final int[] values = {1}; // one non-zero value
  • final int[] values = {1, 1, 1}; // several non-zero values
  • final int[] values = {0, 1, 1}; // zero value first
  • final int[] values = {1, 1, 0}; // zero value last
  • final int[] values = {1, 1, 0, 1, 1, 1}; // longest non-zero sequence at end
  • final int[] values = {1, 1, 1, 0, 1, 1}; // longest non-zero sequence at beginning

Another remedy that does work is for @batmm to move the inner conditional block to a particular place, so that it executes even when the longest sequence of non-zero values occurs at the end of the array.

2 Likes

Not as elegant as GoToLoop’s solution but another approach could consist in converting the original array to a single string, splitting it into sublists at "0" separators and getting the length of the longest one.

This is pretty straightforward in Python mode, but not sure that would translate easily in Java.

Example:

# For arrays of 0 and 1 only
s = [1,0,1,1,0,0,1,1,1,1,0,1]

print len(max(''.join(map(str,s)).split("0"))) # --> 4

# For any array of integers
s = [8,0,4,2,0,0,3,7,1,6,0,9]

print len(max(''.join(map(lambda x:str(int(x>0)),s)).split("0")))  # --> 4
2 Likes

Thanks, @solub. Python is great!

Another Python solution:

def maxNonZeroSequence(nums):
  return max(len(s) for s in ("".join(["0" if n == 0 else "1" for n in nums])).split("0"))

EDIT (2x on April 8, 2021):

So as to provide @batmm with something useful that can easily be converted to Java, here’s a p5.js solution:

function maximumConsecutiveNonZero(nums) {
  let ct = 0; 
  let mx = 0; 
  for (let i = 0; i < nums.length; i += 1) { 
    if (nums[i] == 0) {
      ct = 0;
    } else { 
      ct += 1;
      if (ct > mx) { 
        mx = ct; 
      } 
    }
  }
  return mx;
}
2 Likes

Thank you so much my life saver

2 Likes

Really clear to understand each iteration!

1 Like

Thanks for your reply, @batmm.

After you have either refined your original solution or developed a new one, please post it for us so we can try it out on various cases.

The p5.js function posted above is similar to your original Java version, but it works properly.

Will that work if one of the integers contain a zero e.g. 201?

2 Likes

Hi @javagar ,

Looks like your JavaScript solution doesn’t work ! :wink:

With your function :

console.log(maximumConsecutiveNonZero([0, 0, 1, 0])); // -> 1

(which should be 2)

It’s because you need to remember if you already found a zero before “closing” the previous sequence of zeros.

This is a more conventional solution in Java which can handle all the edges cases :

int maximumConsecutiveNonZero(int[] array) {
  if (array.length == 0) return 0;
  
  boolean alreadyFoundZero = false;

  int maxZeroCount = 0;
  int zeroCount = 1;

  for (int i = 0; i < array.length; i++) {
    // We found a zero
    if (array[i] == 0) {
      if (alreadyFoundZero) { // We are counting a sequence
        zeroCount++;
      } else { // It's the beginning of a sequence
        alreadyFoundZero = true;
        zeroCount = 1;
      }
    } else if (alreadyFoundZero) { // It's not a zero and we were counting a sequence
      // Update the maximum
      if (zeroCount > maxZeroCount) {
        maxZeroCount = zeroCount;
      }
      
      // Stop the sequence
      alreadyFoundZero = false;
    }
  }
  
  // Check if the last element is a zero, if so return the number of zeros
  int lastElement = array[array.length - 1];

  return (lastElement == 0) ? zeroCount : maxZeroCount;
}

And the tests :

final int[] values = {};                 // -> 0
final int[] values = {0};                // -> 1
final int[] values = {0, 0, 0};          // -> 3
final int[] values = {1};                // -> 0
final int[] values = {1, 1, 1};          // -> 0
final int[] values = {0, 1, 1};          // -> 1
final int[] values = {1, 1, 0};          // -> 1
final int[] values = {1, 1, 0, 1, 1, 1}; // -> 1
final int[] values = {1, 1, 1, 0, 1, 1}; // -> 1

Isn’t the function supposed to be looking for maximum runs of non-zero values? If so, then [0, 0, 1, 0] should give us a 1. Maybe we need clarification from @batmm.

2 Likes

Ah my bad you are right! :grinning:

I made the opposite, the maximum number of zero values in an array!!

And your code is actually more compact because you update the maximum each time instead of updating at the end of a non-zero sequence of numbers :yum:

1 Like

Yes, it will. Because the original integers are first converted to 0 and 1 with:

map(lambda x:str(int(x>0)),s)

Example:

s = [1003,702,330,106,0,109]

len(max(''.join(map(lambda x:str(int(x>0)),s)).split('0')))

# --> 4
3 Likes

I couldn’t resist doing this - javascript version

const s = [8,0,4,2,0,0,3,7,1,6,0,9]
const n = Math.max(...s.reduce((a, i) => (i?a[a.length-1]++:a.push(0),a),[0]))
console.log(n)

or

const s = [8,0,4,2,0,0,3,7,1,6,0,9]
const n = Math.max(...s.reduce((a, i) => (i?a[0]++:a.unshift(0),a),[0]))
console.log(n)

or even shorter

const s = [8,0,4,2,0,0,3,7,1,6,0,9]
const n = Math.max(...s.reduce((a, i) => (i?a[0]++:a=[0,...a],a),[0]))
console.log(n)
3 Likes