14

How to find the length of the longest consecutive bit string(either 1 or 0)?

00000000 11110000 00000000 00000000 -> If it is 0 then length will be 20

11111111 11110000 11110111 11111111 -> If it is 1 then length will be 12

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
bithacker
  • 141
  • 1
  • 1
  • 4
  • 2
    @bithacker , don't you mean that "if 0, then length will be 20" ? Also, does this have to the the longest consecutive string AT THE END of the list? This is quite ambiguous. What about 10101111111010101 ? – Aaron McDaid Jul 21 '10 at 23:48
  • @aaron mcdaid you are correct. if 0 the length will be 20. The answer for your other question is 1. The consecutive string can be anywhere. – bithacker Jul 21 '10 at 23:52
  • @bithacker: I've just realised my own example was a bit ambiguous. My current understanding is that 0101000111101010 will be either three or four depending on whether you're looking for zero or one. – Aaron McDaid Jul 21 '10 at 23:55
  • @aaron mcdaid since the longest consecutive string is from 1 so the answer would be 4. – bithacker Jul 22 '10 at 00:09
  • Are you working with strings i.e char arrays, or with ints of some length? – zdav Jul 22 '10 at 00:14
  • What is the size of your array 4 bytes or 32 bytes? – Siddiqui Jul 22 '10 at 12:25
  • I think @bithacker has just helped us clarify something. The signature of the function will be something like "int longest(bytestring b)" The reason I emphasize this is that the programmer does not ask explicitly for ones or zeroes. We just ask for the single longest string, regardless of its type. @bithacker: Once the longest is found, do you simply want to know its length? Or should be return also return a 1 or 0 to signify what type of long string was found? – Aaron McDaid Jul 22 '10 at 21:04
  • input will be array of bytes like { 0x00, 0x01, 0xff, 0xff } and the result should be 17. – bithacker Jul 23 '10 at 01:41
  • size of the above array of bytes is 4. – bithacker Jul 23 '10 at 01:47
  • Well you can use some logical operator like AND, OR, XOR etc or use bit operators like left shift, right shift operator etc. – Siddiqui Jul 23 '10 at 10:58
  • Related: [How to find if there are n consecutive set bits in a 32 bit buffer?](https://stackoverflow.com/q/12053467) – Peter Cordes Apr 16 '22 at 02:36

10 Answers10

27

The following is based on the concept that if you AND a bit sequence with a shifted version of itself, you're effectively removing the trailing 1 from a row of consecutive 1's.

      11101111   (x)
    & 11011110   (x << 1)
    ----------
      11001110   (x & (x << 1)) 
        ^    ^
        |    |
   trailing 1 removed

Repeating this N times will reduce any sequence with N consecutive 1's to 0x00.

So, to count the number of consecutive 1's:

int count_consecutive_ones(int in) {
  int count = 0;
  while (in) {
    in = (in & (in << 1));
    count++;
  }
  return count;
}

To count the number of consecutive 0's, simply invert and the same routine.

int count_consecutive_zeros(int in) {
  return count_consecutive_ones(~in);
} 

Proof of concept: http://ideone.com/Z1l0D

int main(void) {
  printf("%d has %d consecutive 1's\n", 0, count_consecutive_ones(0));
  printf("%d has %d consecutive 0's\n", 0, count_consecutive_zeros(0));

  /* 00000000 11110000 00000000 00000000 -> If it is 0 then length will be 20 */
  printf("%x has %d consecutive 0's\n", 0x00F00000, count_consecutive_zeros(0x00F00000));

  /* 11111111 11110000 11110111 11111111 -> If it is 1 then length will be 12 */
  printf("%x has %d consecutive 1's\n", 0xFFF0F7FF, count_consecutive_ones(0xFFF0F7FF));
}

Output:

0 has 0 consecutive 1's
0 has 32 consecutive 0's
f00000 has 20 consecutive 0's
fff0f7ff has 12 consecutive 1's
Shawn Chin
  • 84,080
  • 19
  • 162
  • 191
  • Thanks for this answer as it is useful here, https://www.hackerrank.com/challenges/30-binary-numbers – Prashant Chikhalkar Jun 24 '16 at 10:56
  • I'd recommend `unsigned int`, to avoid signed-integer overflow undefined behaviour when you shift a `1` bit into the sign bit. (ISO C does not define the behaviour there, but most C implementations do. e.g. [GNU C does](https://gcc.gnu.org/onlinedocs/gcc/Integers-implementation.html#Integers-implementation) unless you use `-fsanitize=shift` or `-fsanitize=undefined`.) int->unsigned conversion is always well-defined, and for 2's complement machines preserves the bit-pattern, so the result will be identical. – Peter Cordes Apr 16 '22 at 02:28
  • https://catonmat.net/low-level-bit-hacks is a good intro to how bithacks like this work, especially ones using + or - for carry propagation. – Peter Cordes Apr 16 '22 at 02:32
6

One simple way would be to simply loop over the bits, and keep track of the number of bits in a row which have had the same value, and the maximum that this value has reached.

Here's a simple C function which does just this:

int num_conseq_matching_bits(int n) {
    int i, max, cur, b, prevb;
    prevb = n & 1; /* 0th bit */
    cur = 1;
    max = 1;
    for(i=1; i<32; i++) {
        b = (n >> i) & 1; /* get the i'th bit's value */
        if(b == prevb) {
            cur += 1;
            if(cur > max)
                max = cur;
        }
        else {
            cur = 1; /* count self */
            prevb = b;
        }
    }
    return max;
}
David Underhill
  • 15,896
  • 7
  • 53
  • 61
  • 4
    I did the downvote. I have since undone the downvote. It's not that I doubt the accuracy of the solution, it's just that it seems unhelpful. I assume that anybody asking this question is easily able to implement a correct, but very slow, solution themselves. I suspected the questioner needs something fast. But now I'm not so sure. So, I'll think I'll hold my fire for now, and neither upvote nor downvote. – Aaron McDaid Jul 22 '10 at 23:23
  • 1
    Fair enough. Since the question didn't ask for a fast solution, I just went with a simple and straightforward one. Correctness first :). – David Underhill Jul 23 '10 at 00:05
  • 1
    @AaronMcDaid if I could I would downvote your comment :) It is quite trivial to see that **there is no faster algorithm than O(number of digits)** (and I speak about algorithm now, not implementation) – Tomas Nov 26 '13 at 18:27
  • 2
    it's not so obvious to me. bit tricks (.. and algorithms) are often times non intuitive. – Jules G.M. Jan 31 '14 at 02:10
  • @TMS can you tell me the subtle difference between algorithm and implementation? – inetknght Jun 06 '15 at 12:53
  • @inetknght if you speak about the algorithm and its *speed*, you usually are satisified with terms like *O(n)*, and you are not concerned about the actual runtime, whether you track field or use bitwise operations etc. When you speak about the implementation and its speed, you usually *are* interested in actual runtime and implementation details like using bitwise ops etc. because they can be crucial for the speed. – Tomas Jun 19 '15 at 14:09
  • Ahh that makes sense. – inetknght Jun 19 '15 at 17:44
  • @Tomas: As Shawn Chin's answer shows, an O(result) algorithm is possible, not O(int_width), assuming you can do shift/and on a whole int_width at once in constant time. Don't be so quick to assume that you have to loop through the bits one at a time, vs. using bitwise operations to check stuff about every possible substring, wherever it might be located. – Peter Cordes Apr 16 '22 at 02:21
3

You can form a look up table to do it quickly for you. The bigger the table, the faster the lookup. 2x256 entry tables can do 8 bits at a time with a little bit twiddling. Add a 1s version of the table and start adding entries. That's probably how I'd go about it.

Michael Dorgan
  • 12,453
  • 3
  • 31
  • 61
2

To use the table idea, you need something like

static struct {
    int lead;  /* leading 0 bits */
    int max;   /* maximum 0 bits */
    int trail; /* trailing 0 bits */
} table[256] = { ....data.... };

int mostConsecutiveBits(unsigned char *str, int length, bool count_ones) {
    int max = 0; /* max seen so far */
    int trail = 0; /* trailing 0s from previous bytes */
    while (length-- > 0) {
        int byte = *str++;
        if (count_ones)
            byte ^= 0xff;
        if (table[byte].max > max)
            max = table[byte].max;
        if (trail + table[byte].lead > max)
            max = trail + table[byte].lead;
        if (byte)
            trail = table[byte].trail;
        else
            trail += 8;
    }
    return max;
}

initializing the table is straight-forward, but depends on your bit- and byte-ordering (little endian or big endian).

Chris Dodd
  • 119,907
  • 13
  • 134
  • 226
0

I don't agree with the tables idea, because I was trying it and realized that even though "BA" in ASCII would contain 5 consecutive 0's for 'B' and 5 consecutive 0's for 'A', they will not add together for 10 consecutive 0's. As a matter of fact, there would be 5 consecutive 0's maximum. (This was in reference to a simple "counting bits in a table idea." Chris Dodd has since expounded on how a table could be used accurately.)

I would use an algorithm like this:

#include <iostream>
#include <algorithm>

using namespace std;

// Assumes Little Endian architecture
int mostConsecutiveBits(char str[], int length) {
    int currentConsecutiveBits=0; 
    int maxConsecutiveBits=0; 
    char currentBit;
    char lastBit=0; 
    char currentChar=str[0];
    int charCtr,bitCtr; 

    for (charCtr=length-1; charCtr>=0; charCtr--) {

        currentChar=str[charCtr];

        for (bitCtr=0; bitCtr<8; bitCtr++) {
            currentBit=currentChar & 1;

            if (currentBit!=lastBit) {
                maxConsecutiveBits=max(maxConsecutiveBits,currentConsecutiveBits);
                currentConsecutiveBits=1; 
                lastBit=currentBit;
            }
            else {
                currentConsecutiveBits++;
            }

            currentChar=currentChar>>1; 

        }
        maxConsecutiveBits=max(maxConsecutiveBits,currentConsecutiveBits);
    }

    return maxConsecutiveBits; 
}   


int main (int argc, char * const argv[]) {
    cout << mostConsecutiveBits("AB",2);
    return 0;
}

In this algorithm, I assume the bitstream is represented as 8-bit characters. For each character, I look at the very last bit with a bitwise AND. If it's the same as the last bit, then I up the consecutive bit count, otherwise, I reset the count because the bits are no longer consecutive. I then use a bitwise shift operation to move the next bit in the character over for observation. Hope this helps!

My answer is effectively a duplicate of David Underhill's answer. :)

froggythefrog
  • 512
  • 1
  • 4
  • 16
  • He has a char array of bytes, probably each byte is either '0' or '1', allowing you to make your solution even shorter. – earlNameless Jul 22 '10 at 00:46
  • Oops.... forgot, of all things, to actually keep track of the biggest number of consecutive 0's, so I added in max_consecutive0s. This is the value you'd want to return, print, etc. – froggythefrog Jul 22 '10 at 02:58
  • @earlNameless: But then what fun would it be without bitwise operations? :) – froggythefrog Jul 22 '10 at 02:59
  • @froggythefrog, true, I'd give up some sanity for fun – earlNameless Jul 22 '10 at 11:23
  • @froggythefrog your logic fails for the below. { 0x01, 0xff, 0x00, 0xff } should return 9 { 0x00, 0x01, 0xff, 0xff } should return 17 are u assuming little endian or big endian? – bithacker Jul 23 '10 at 01:39
  • @bithacker Doh! I see the problem. I am traversing the characters in the wrong order, so despite the fact I am looking at the bits in each character from right to left, I am traversing the characters from right to left. With my next edit, my code sample will have a for loop that traverses the characters from length-1 to 0. I wrote this program and ran it on a couple of Intel i586's, which are little endian. I was assuming that the leftmost bit would carry over the one on a right-shift. – froggythefrog Jul 24 '10 at 22:12
0

Since you didn't wrote what is bit string (regular int, byte array or char string I've assumed that it's char array

int maxConsBits(char *pStr,char cChar)
{
    char curChar;
    int curMax = 0;
    int max = 0;
    while (pStr)
    {
       if (*pStr == cChar)
       {
          curMax++;
          if (curMax > max)
          {
             max = curMax;
          }
       }
       else
       {        
           curMax = 0;
       }
       pStr++;
   }
   return max;
}
XAder
  • 676
  • 4
  • 12
0

Posting from iPhone withbig fingers.

If ones, then invert.

Loop over the input using a leadz function. For each iteration, shift the input to the left. Continue until you reach the end of the input. Note that you need to compare the original input length with the cumulative leadz counts.

Also, as an optimization, you can early abort when the remaining input length is less than the largest leadz you have seen.

There are many fast leadz algorithms online.

No One in Particular
  • 2,846
  • 4
  • 27
  • 32
0

If you're just looking for a byte string of four bytes, you can pack these into an unsigned long and use an algorithm like this:

int CountConsecutiveOnes(unsigned long n)
{
    unsigned long m = n;
    int k = 0;

    while (m)
    {
        ++k;
        n >>= 1;
        m &= n;
    }

    return k;
}

For counting zeros, just taking the bitwise complement first.

If you need to count byte strings longer than four, you can just implement the operations x >>= 1 and x & y either directly on the byte strings or it may be more efficient to use strings of unsigned long so the carry checks on the implementation of x >>= 1 aren't too expensive.

CB Bailey
  • 755,051
  • 104
  • 632
  • 656
0

It may help you.... First convert your binary number to String say bits. It will give you max number of consecutive 1's (in java)

String[] split = bits.split("0");
Arrays.sort(split);
int maxLength = split[split.length - 1].length();
Harish
  • 1,841
  • 1
  • 13
  • 26
0
public static int maxConsecutiveOneInBinaryNumber(int number) {
int count = 0;
int max = 0;
while (number != 0) {
  if ((number & 1) == 1) {
    count++;
  } else {
    max = Math.max(count, max);
    count = 0;
  }
  number = number >> 1;
}
return Math.max(count, max);
}

You can this code here: https://github.com/VishalSKumar/DSFiddle/blob/master/src/main/java/com/vishalskumar/hackerrank/MaxConsecutiveOneInBinary.java

Constantine
  • 1,356
  • 14
  • 19