'Solving Binary Gap using Recursion

I am trying to solve binary gap problem using recursion. It can be easily solved without recursion. But I want to solve this with recursion.The below program takes an integer as input and finds the binary gap.

Example:

input= 9, Binary form = 1001, Answer = 2

input=37, Binary form = 100101, Answer = 2

It finds the maximum number of zeros that occur between two 1's in the binary representation.

I want to solve this in O(logn). Right now, the below program simply counts the total number of zeros and gives output 3 instead of 2. How do I correct this to get the right output?

class BinaryGap {

    public int solution(int N){

     return solution(N, false, 0);   
    }
    public int solution(int N, boolean prevFlag, int memo) {

        if(N<2)
            return 0;

        int remainder = N%2 ;


        if(prevFlag){
            if(remainder == 0){
                memo = 1 + solution(N/2, prevFlag, memo);
            } else {
                int newGap = solution(N/2, prevFlag, memo);

                if(newGap > memo)
                    memo = newGap;
            }
        } else {

            prevFlag = (remainder == 1);
            return solution(N/2, prevFlag, 0);
        }

        return memo;

    }

    public static void main(String args[]){
        BinaryGap obj = new BinaryGap();

        System.out.println(obj.solution(37));
    }

}


Solution 1:[1]

In Java 8, you can use stream to solve this:

static int calculateBinaryGap(int N) {
    return Stream
        .of(
            // integer to binary string
            Integer.toBinaryString(N)
                // trim 0(s) at the end
                .replaceAll("0+$", "")
                // split string with 1(s)
                .split("1+"))
        // lambda expressions: use filter to keep not null elements
        .filter(a -> a != null)
        // method references: convert string to integer by using the
        // length of string
        .map(String::length)
        // method references: find the largest number in the stream by
        // using integer comparator
        .max(Integer::compare)
        // return 0 if nothing matches after the process
        .orElse(0);
    }

There is a good article about Streams: Processing Data with Java SE 8 Streams

Solution 2:[2]

As many people were facing problem in handling the trailing zeros condition of the solution. Below is my solution with 100% test cases passing.

class Solution {
    public int solution(int N) {
        // write your code in Java SE 8
        return binaryGap(N,0,0,0);
    }
    public int binaryGap(int n, int counter, int max, int index){
        if(n==0)
            return max;

        if(n%2==0 && index==0)
            index=0;

        else if(n%2==0)
            counter ++;
        else {
            max = Math.max(counter, max);
            index++;
            counter =0;
        }
        n = n/2;

        return binaryGap(n, counter, max, index);
    }

}

Solution 3:[3]

My solution. 100% without recursion.

class Solution {
        public int solution(int N) {
            String binary = Integer.toString(N, 2);
            int largestGap = 0;
            for (int i = 1, gap = 0; i < binary.length(); i++) {
                while (i < binary.length() && binary.charAt(i) == '0') {
                    i++;
                    gap++;
                }

                if (gap > largestGap && i < binary.length()) {
                    largestGap = gap;
                }

                gap = 0;
            }
            return largestGap;
        }
    }

Solution 4:[4]

We can split the binaryString with 1 as the delimiter

Eg: N=1041 BinaryString = 10000010001

When its split based on 1 as delimiter we get [, 00000, 000]

and then the subproblem becomes to find the array with largest length

private static int solution(int N) {
        int gap = 0;
        String binaryStr = Integer.toBinaryString(N);

        String[] zeroArrays = binaryStr.split("1");
        System.out.println(Arrays.toString(zeroArrays));
        for(String zeroArray : zeroArrays) {
            gap = zeroArray.length() > gap ? zeroArray.length() : gap;
        }   
        return gap;
    }

Solution 5:[5]

This answer is tested on coditilty and it has got 100% for performance and correctness.

Hope it will help someone.

    public static int solution(int N) {
    int binaryGap = 0;

    String string = Integer.toBinaryString(N).replaceAll("0+$", "");

    String[] words = string.split("1+");

    Arrays.sort(words);

    if(words.length != 0) {
        binaryGap = words[words.length -1].length(); 
    }

    return binaryGap;

}

Solution 6:[6]

Ruby Solution (No recursion - 100% correctness in Codility):

`

def binary_gap(number)
      remainder = []
      while number > 0
        remainder << number % 2
        number = number / 2
      end
      binary_number = remainder.reverse.join('')
      biggest_gap = 0
      current_gap = 0
      status ='stop'
      binary_number.reverse.each_char do |char|
        if char =='1'
          status = 'start'
          current_gap = 0
        elsif char == '0' && status =='start'
          current_gap +=1
        end
        if current_gap > biggest_gap
          biggest_gap = current_gap
        end
      end

      return biggest_gap

    end

`

Solution 7:[7]

I think @saka1029 is almost there, just like @xuesheng said that solution will not work if the input for example are 2 = 010, 4 = 100, 6 = 110.

I would like to suggest do this below instead

static int solution(int n) {
    return solution(n, 0, 0, 0);
}

static int solution(int n, int max, int current, int index) {
    if (n == 0)
        return max;
    else if (n % 2 == 0 && index == 0)
        return 0;
    else if (n % 2 == 0 && index > 0)
        return solution(n / 2, max, current + 1, index + 1);
    else
        return solution(n / 2, Math.max(max, current), 0, index + 1);
}

Solution 8:[8]

Objective C Solution

int solution(int N) {
    if (N==0)
    {
        return 0;
    }
    int maximumGap = -1;
    int currentGap = 0;
    while(N>0)
    {
        if (N%2 == 1)
        {
            if (currentGap>0)
            {
                maximumGap = maximumGap>currentGap?maximumGap:currentGap;
            }else
            {
                maximumGap = 0;
            }
            currentGap = 0;
        }
        else if(maximumGap>-1)
        {
            currentGap++;
        }
        N=N/2;
    }
    return maximumGap;
}

Solution 9:[9]

Java Solution (No recursion - 100% correctness in Codility):

public static int solution(Integer number) {

    String binary = Integer.toBinaryString(number);

    String[] gaps = binary.split("1");

    String biggestGap ="";
    for (int i = 0; i < (binary.endsWith("1") ? gaps.length: gaps.length-1); i++) {

        if (gaps[i].contains("0") && gaps[i].length()>biggestGap.length())
        biggestGap = gaps[i];

    }

    return biggestGap.length();
}

Solution 10:[10]

I got this solution without using recursion.

def solution(N):
    number = str(bin(N))[2:]

    current = 0
    max_ = 0
    started = False
    for e in number[::-1]:
        if e == '1':
            started = True
            if current > max_:
                max_ = current
            current = 0
        else:
            if started:
                current = current + 1
    return max_

Solution 11:[11]

The optimal solution that takes in account the boundaries and exceptional scenarios like: Given N = 32 the function should return 0, because N has binary representation '100000' and thus no binary gaps. But most code I have seen above will returns 5. Which is wrong. Here is an optimal solution that passes all tests:

public int solution(int N) {
        int result = 0;
        while (N > 0) {
            if ((N & 1) == 1) {
                int temp = 0;
                while ((N >>= 1) > 0 && ((N & 1) != 1)) {
                    temp++;
                }
                result = Math.max(result, temp);
            } else {
                N >>= 1;
            }
        }
        return result;
    } 

Solution 12:[12]

My Javascript ES6 Solution with default function parameter

Also handled all possible errors

  function solution(N = 0) {
     N = +N;
     if (N !== N) {
       return 0;
     }

    const binaryList = N.toString(2).split("");
    let maxGap = 0;
    let currentGap = 0;

    binaryList.forEach(item => {
      if (item === "0") {
         current++;
      } else {
       if (currentGap > maxGap) {
          maxGap = currentGap;
       }
       currentGap = 0;
     }
   });

    return max;
  }

Solution 13:[13]

def solution(N):

  max_gap = 0
  current_gap = 0

  # Skip the tailing zero(s)
  while N > 0 and N % 2 == 0:
      N //= 2

  while N > 0:
      remainder = N % 2
      if remainder == 0:
          # Inside a gap
          current_gap += 1
      else:
          # Gap ends
          if current_gap != 0:
              max_gap = max(current_gap, max_gap)
              current_gap = 0
      N //= 2

  return max_gap
if __name__ == '__main__':
    solution(N)

// Test Cases:
// N = 9 (1001), Expected = 2
// N = 529 = (1000010001), Expected = 4
// N = 51272 (1100100001001000), Expected = 4
// N = 15 (1111), Expected = 0
// N = 53 (110101), Expected = 1
// N = 2147483647 (1111111111111111111111111111111), Expected = 0
// N = 2147483648 (10000000000000000000000000000000), Expected = 0
// N = 0 (0), Expected = 0
// N = -1 (null), Expected = 0
// N = "A" (null), Expected = 0
// N = null (null), Expected = 0
// N = [blank] (null), Expected = 0

Solution 14:[14]

The solution by hemantvsn is great except the trailing zeros which need to be removed

private static int solution(int N) {
            int gap = 0;
            String binaryStr = Integer.toBinaryString(N);

            String[] zeroArrays = binaryStr.split("1");

            String[] zeroTruncated = new String[0];

            System.out.println(Arrays.toString(zeroArrays));
            if (Integer.lowestOneBit(N) != 1) {
                zeroTruncated = Arrays.copyOf(zeroArrays, zeroArrays.length-1);

            }
            for(String zeroArray : zeroTruncated) {
                gap = zeroArray.length() > gap ? zeroArray.length() : gap;
            }
            return gap;
        }

Solution 15:[15]

try this. I'm tyring without using recursive.

private static int binaryGap(int N){
    int gap1 = 0, gap2 = 0, gapCounter = 0;

    for(int i = N; i>=0; i--)
    {
        if(N < 1) break;

        //binary 0
        if(N%2 == 0) {
            gap1++;
        }
        //binary 1
        else
        {
            gap2 = gap2 > gap1 ? gap2 : gap1;
            gap1 = 0;
            gapCounter++;
        }
        if(gapCounter==1) gap2=0;
        N = N/2;
    }
    return gap2;
}

Solution 16:[16]

// you can write to stdout for debugging purposes, e.g.
// printf("this is a debug message\n");

int solution(int N) {
   int b;
    int zeroCounter = 0;
    int prev = 0;
    int c = -1;
    while (N) {
        b = N % 2;
        N = N / 2;
        if ((b==1)||(c==0)) {
           c=0;

            //printf("%d", b);
            if (b == 1) {

                //printf("%d", b);
                //checkTrailZero=prev;
                if (prev < zeroCounter) {
                    prev = zeroCounter;
                }
                zeroCounter = 0;
            } else {

                zeroCounter++;
            //  printf("--%d--", zeroCounter);
            }
        }
    }
    //printf("longest%d", prev);
    return prev;}

Solution 17:[17]

Here is working code with all the test cases passed,

package org.nishad;

import java.util.Arrays;

public class BinaryGap {
    public static void main(String[] args) {
        int N = 1;
        int result;
        //converting integer to binary string
        String NString = Integer.toBinaryString(N);
        //Removing the Trailing Zeros
        NString = NString.replaceFirst("0*$","");
        //Split the binary string by one or more one(regex) for arrays of zeros 
        String[] NStrings = NString.split("1+");
        //Storing the array length
        int length = NStrings.length;

        if(length==0) // if length is zero no gap found 
            result = length;
        else          
            {
            //Sorting the array to find the biggest zero gap
            Arrays.sort(NStrings, (a, b)->Integer.compare(a.length(), b.length()));
            result = NStrings[length-1].length();
            }


        System.out.println(NString);

        System.out.println(result);
    }
}

Solution 18:[18]

Please just do it:

class Solution {
    public int solution(int N) {
        int gap = 0;
        int current = -1;

        while(N>0) {
            if(N%2!=0) {
               if(current>gap)
                    gap = current;
                current = 0;
            } else if(current>=0){
                 current++;

            }
            N=N>>1;
            }

            return gap;
    }
}

The definitive!

Thanks!!!!

Solution 19:[19]

Javascript solution during Decimal to binary conversion.

function solution(N) {
    let maxGap = 0, currentSegmentGap = 0;

    let init = false;   

    while(N > 0) {
        const binDgt = N%2;

        if(binDgt) {
            currentSegmentGap = 0;
            init = true;

        } else if(init) {
            currentSegmentGap++;
            maxGap = maxGap > currentSegmentGap? maxGap: currentSegmentGap;
        }

        N = Math.floor(N/2);
    }
    return maxGap;
}

Solution 20:[20]

Java Solution (100% correctness in Codility)

int solution(int N) {
    int tempGap=0, gap=0;
    String binaryString = Integer.toBinaryString(N);
    int i =0;
    while(i < binaryString.length())    {
        if(binaryString.charAt(i) == '1')   {
            // initialize tempGap to hold binary gap temporarily and increment the index pointing to binary array
            ++i;
            tempGap = 0;
            // move until we encounter '1' or end of array is reached
            while(i < binaryString.length() && binaryString.charAt(i) != '1')    {
                ++i;
                tempGap++;
            }
            // in case, end of array is reached but we did not find '1'
            if (i >= binaryString.length())    {
                tempGap = 0;
            }
        } else  {
            ++i;
        }
        if (tempGap>gap)    {
            gap = tempGap;
        }
    }
    return gap;
}

Solution 21:[21]

My solution is written in Swift 4 with a totally different logic (without recursion), which finds the longest binary gap, also facilitates finding the current binary gap. 100% test cases passed.

Complexity: O(n)

public func solution(_ N : Int) -> Int {

    var arrayOfIndexes:[Int] = []
    let binaryString = String(N, radix:2)

    print("Binary String of \"\(N)\" is: \"\(binaryString)\"")

    var longestBinaryGap:Int = 0
    var index = 0

    for char in binaryString {
        if char == "1" {
            arrayOfIndexes.append(index)
            let currentBinaryGap = getCurrentBinaryGapFor(arrayOfIndexes)
            if arrayOfIndexes.count == 2 {
                longestBinaryGap = currentBinaryGap
            } else if index > 2 {
                if currentBinaryGap > longestBinaryGap {
                    longestBinaryGap = currentBinaryGap
                }
            }
        }
        index += 1
    }

    print("Position of 1's: \(arrayOfIndexes)")
    return longestBinaryGap
}

func getCurrentBinaryGapFor(_ array:[Int]) -> Int {
    var currentBinaryGap = 0
    if array.count >= 2 {
        let currentPosition = array.count - 1
        let previousPosition = currentPosition - 1
        currentBinaryGap = array[currentPosition] - array[previousPosition] - 1
        return currentBinaryGap
    } else {
        return currentBinaryGap
    }
}

Sample test cases with output:

Binary String of "2" is: "10"
Position of 1's: [0]
The longest binary gap is 0

Binary String of "4" is: "100"
Position of 1's: [0]
The longest binary gap is 0

Binary String of "6" is: "110"
Position of 1's: [0, 1]
The longest binary gap is 0

Binary String of "32" is: "100000"
Position of 1's: [0]
The longest binary gap is 0

Binary String of "170" is: "10101010"
Position of 1's: [0, 2, 4, 6]
The longest binary gap is 1

Binary String of "1041" is: "10000010001"
Position of 1's: [0, 6, 10]
The longest binary gap is 5

Binary String of "234231046" is: "1101111101100001010100000110"
Position of 1's: [0, 1, 3, 4, 5, 6, 7, 9, 10, 15, 17, 19, 25, 26]
The longest binary gap is 5

Solution 22:[22]

@saka1029 has provided a nice solution but it does not cover all the test cases. Here is a solution that covers all cases.

public int solution(int N) {

    return solution(N, 0, 0, false);
}

static int solution(int n, int max, int count, boolean isOn) {
    if (n == 0)
        return max;
    else if (n % 2 == 0){
        count = isOn? count+1 : count;
        return solution(n / 2, max, count, isOn);
    }
    else{
        isOn=true;
        max = count>max?count:max;
        return solution(n / 2, Math.max(max, count), 0, isOn);
    }
}

Solution 23:[23]

Here is another Java solution (recursive and iterative versions) with O(log n) time complexity and 100% correctness, i.e. handling the trailing zeros condition, which avoids the use of the integer binary string.

Recursive:

class Solution {

    public int solution(int N) {
        return binaryGapRecursive(N, 0, null);
    }

    private int binaryGapRecursive(int n, int maxGap, Integer currentGap) {
        int quotient = n / 2;

        if (quotient > 0) {
            int remainder = n % 2;

            if (remainder == 1) {
                if (currentGap != null) {
                    maxGap = Math.max(maxGap, currentGap);
                }
                currentGap = 0;

            } else if (currentGap != null) {
                currentGap++;
            }

            return binaryGapRecursive(quotient, maxGap, currentGap);

        } else {
            return currentGap != null ? Math.max(maxGap, currentGap) : maxGap;
        }
    }

}

Iterative:

class Solution {

    public int solution(int n) {
        int maxGap = 0;
        Integer currentGap = null;

        while (n > 0) {
            int remainder = n % 2;

            if (remainder == 1) {
                if (currentGap != null) {
                    maxGap = Math.max(maxGap, currentGap);
                }
                currentGap = 0;

            } else if (currentGap != null) {
                currentGap++;
            }

            n = n / 2;
        }

        return currentGap != null ? Math.max(maxGap, currentGap) : maxGap;
    }

}

Solution 24:[24]

I'm tyring code

import java.util.Random;
import java.util.concurrent.ThreadLocalRandom;

public class Solution {
    public int solution(int N) {
        // write your code in Java SE 8
        int result = 0;
        // ?? 2??? ??
        String binary = Integer.toBinaryString(N);
        // ??? 1 ??
        int firstOneIdx = 0;
        // ?? 1 ??
        int nextOneIdx = 0;

        // ?? loop? 2?? ??? ??
        for (int i = 0; i <= binary.length(); i++) {

            // ???? ??? ??
            if (i == 0) {
                firstOneIdx = binary.indexOf("1");
            }

            // ??? ??? ?? 1 ??
            nextOneIdx = binary.indexOf("1", firstOneIdx + 1);

            // ?? 1? ??? loop ??
            if (nextOneIdx == -1) {
                break;
            }

            // ?
            int temp = nextOneIdx - firstOneIdx - 1;

            // ?? ?? ???? ?? ?? ??
            if (temp > result) {
                result = temp;
            }

            // ??? ???? ??
            firstOneIdx = nextOneIdx;
        }

        return result;
    }

    public static void main(String[] args) {
        Solution solution = new Solution();

        Random random = ThreadLocalRandom.current();

        for (int i = 0; i< 10000; i++){

            int input = random.nextInt(2147483647);
            int result = solution.solution(input);

            System.out.println("input = "+input+" result = "+result);
        }

    }
}

Solution 25:[25]

class Solution { //Java Solution (100% correctness in Codility)

public int solution(int N) {
    // write your code in Java SE 8

    Integer candidate = new Integer(N);
    String binStr = candidate.toBinaryString(N);
    char[] binArr = binStr.toCharArray();
    // System.out.println("Binary String: " + binStr);

    char c, c1;
    int counter = 0;

    for (int i = 0; i < binStr.length();) {
        // c = binStr.charAt(i);
        c = binArr[i];
        // System.out.println("c: " + c);
        i++;
        if (c == '1') {
            int tempCounter = 0;
            for (int j = 0, k = i; j < binStr.length() - 1; j++, k++) {

                if (i < binStr.length()) {
                    c1 = binArr[i];
                } else {
                    break;
                }

                // System.out.println("c1: " + c1);
                if (c1 == '1') {

                    if (counter < tempCounter)
                        counter = tempCounter;

                    break;
                } else {
                    // System.out.println("inside counter...");
                    tempCounter++;
                    i++;
                }
                // i=k;
            }
        }

    }

    // System.out.println("Counter: " + counter);
    return counter;

}

}

Solution 26:[26]

Kotlin solution:

fun binaryGap(number: Int): Int {
    return number.toString(2)
            .trimEnd { it == '0' }
            .split("1")
            .map { it.length }
            .max() ?: 0
}

Solution 27:[27]

Here is the perfect solution 100 out of 100 point using Java and recursion. It did pass test of n = 128 with binary value of 10100101 and the ans. 2 and n = 592 with binary value of 1001010000 and the ans. 2.

class Solution {
    public int solution(int n) {
        return solution(n, 0, 0, 0);
    }

    static int solution(int n, int max, int current, int ones) {
        if (n == 0) {
            return max;
        } else if (n % 2 == 0) {
            return solution(n / 2, max, ++current, ones);
        } else {
            max = ones == 0 ? ones : Math.max(max, current);
            return solution(n / 2, max, 0, ++ones);
        }
    }
}

enter image description here

Solution 28:[28]

100% Binary Gap solution without recursion

public static int solution(int N) {

String binary = Integer.toString(N, 2);
int length = binary.length();
int trailingZeros = 0;

// Get the length of trailing zeros
for (int i = length - 1; i > 0; i--) {

  if (binary.charAt(i) == '0') {
    trailingZeros++;
  }

  else if (binary.charAt(i) == '1') {
    break;
  }
}
// length of binary string to consider
int lengthToConsider = length - trailingZeros;

System.out.println(lengthToConsider);

int highestGap = 0;
int zeroGapCount = 0;

for (int i = 1; i < lengthToConsider; i++) {
  // Count all subsequent zeros
  if (binary.charAt(i) == '0') {
    zeroGapCount++;
  }

  // else if 1 found then calculate highestGap as below
  else if (binary.charAt(i) == '1') {
    if (highestGap <= zeroGapCount) {
      highestGap = zeroGapCount;
    }
    // make the zeroGapCount as zero for next loop
    zeroGapCount = 0;
  }
}

return highestGap;

}

Solution 29:[29]

Here is my solution without recursion. 100% tests are passed in Codability's application

public class Solution {

    int counter = 0;
    Set<Integer> binaryGap = new HashSet<>();
    String binaryNumber;

    public int solution(int N) {
        binaryNumber = convert2Binary(N);

        IntStream.range(1, binaryNumber.length())
                .boxed()
                .forEach(calculateBinaryGapConsumer);

        return getMaxBinaryGap();
    }

    private String convert2Binary(int N) {
        return Integer.toBinaryString(N);
    }

    Consumer<Integer> calculateBinaryGapConsumer = i -> {
        char currentChar = binaryNumber.charAt(i);
        char previousChar = binaryNumber.charAt(i-1);
        if (previousChar == '1' && currentChar == '0') {
            increaseCounter();
        } else if (previousChar == '0' && currentChar == '0') {
            increaseCounter();
        } else if (previousChar == '0' && currentChar == '1') {
            saveBinaryGap();
            makeCounterZero();
        }
        //No need to handle case previousChar == '1' && currentChar == '1'.
    };

    private void saveBinaryGap() {
        binaryGap.add(counter);
    }

    private void increaseCounter() {
        counter++;
    }

    private void makeCounterZero() {
        counter = 0;
    }

    private int getMaxBinaryGap() {
        return binaryGap.stream().mapToInt(v->v).max().orElse(0);
    }

}