First element greater than or equal to X in prefix sum of N numbers using Binary Lifting
Last Updated :
23 Jun, 2021
Given an array of N integers and a number X. The task is to find the index of first element which is greater than or equal to X in prefix sums of N numbers.
Examples:
Input: arr[] = { 2, 5, 7, 1, 6, 9, 12, 4, 6 } and x = 8
Output: 2
prefix sum array formed is { 2, 7, 14, 15, 21, 30, 42, 46, 52}, hence 14 is the number whose index is 2
Input: arr[] = { 2, 5, 7, 1, 6, 9, 12, 4, 6 } and x = 30
Output: 5
Approach: The problem can be solved using lower_bound function in Binary search. But in this post, the problem will be solved using Binary-Lifting. In binary lifting, a value is increased (or lifted) by powers of 2, starting with the highest possible power of 2(log(N)) down to the lowest power(0).
- Initialize position = 0 and set each bit of position, from most significant bit to least significant bit.
- Whenever a bit is set to 1, the value of position increases (or lifts).
- While increasing or lifting position, make sure that prefix sum till position should be less than v.
- Here, log(N) bits are needed for all possible values of ‘position’ ( from log(N)th to 0th bit ).
- Determine the value of the i-th bit. First, check if setting the i-th bit won’t make ‘position’ greater than N, which is the size of the array. Before lifting to the new ‘position’, check that value at that new ‘position’ is less than X or not.
- If this condition is true, then target position lies above the ‘position’ + 2^i, but below the ‘position’ + 2^(i+1). This is because if the target position was above ‘position’ + 2^(i+1), then the position would have been already lifted by 2^(i+1) (this logic is similar to binary lifting in trees).
- If it is false, then the target value lies between ‘position’ and ‘position’ + 2^i, so try to lift by a lower power of 2. Finally, the loop will end such that the value at that position is less than X. Here, in this question, the lower bound is asked. So, return ‘position’ + 1.
Below is the implementation of the above approach:
C++
#include <bits/stdc++.h>
using namespace std;
void MakePreSum( int arr[], int presum[], int n)
{
presum[0] = arr[0];
for ( int i = 1; i < n; i++)
presum[i] = presum[i - 1] + arr[i];
}
int BinaryLifting( int presum[], int n, int x)
{
int pos = 0;
int LOGN = log2(n);
if (x <= presum[0])
return 0;
for ( int i = LOGN; i >= 0; i--) {
if (pos + (1 << i) < n &&
presum[pos + (1 << i)] < x) {
pos += (1 << i);
}
}
return pos + 1;
}
int main()
{
int arr[] = { 2, 5, 7, 1, 6, 9, 12, 4, 6 };
int x = 8;
int n = sizeof (arr) / sizeof (arr[0]);
int presum[n] = { 0 };
MakePreSum(arr, presum, n);
cout << BinaryLifting(presum, n, x);
return 0;
}
|
Java
import java.util.*;
class solution
{
static void MakePreSum( int []arr, int []presum, int n)
{
presum[ 0 ] = arr[ 0 ];
for ( int i = 1 ; i < n; i++)
presum[i] = presum[i - 1 ] + arr[i];
}
static int BinaryLifting( int []presum, int n, int x)
{
int pos = 0 ;
int LOGN = ( int )Math.log(n);
if (x <= presum[ 0 ])
return 0 ;
for ( int i = LOGN; i >= 0 ; i--) {
if (pos + ( 1 << i) < n &&
presum[pos + ( 1 << i)] < x) {
pos += ( 1 << i);
}
}
return pos + 1 ;
}
public static void main(String args[])
{
int []arr = { 2 , 5 , 7 , 1 , 6 , 9 , 12 , 4 , 6 };
int x = 8 ;
int n = arr.length;
int []presum = new int [n];
Arrays.fill(presum, 0 );
MakePreSum(arr, presum, n);
System.out.println(BinaryLifting(presum, n, x));
}
}
|
Python 3
import math
def MakePreSum( arr, presum, n):
presum[ 0 ] = arr[ 0 ]
for i in range ( 1 , n):
presum[i] = presum[i - 1 ] + arr[i]
def BinaryLifting(presum, n, x):
pos = 0
LOGN = int (math.log2(n))
if (x < = presum[ 0 ]):
return 0
for i in range (LOGN, - 1 , - 1 ) :
if (pos + ( 1 << i) < n and
presum[pos + ( 1 << i)] < x) :
pos + = ( 1 << i)
return pos + 1
if __name__ = = "__main__" :
arr = [ 2 , 5 , 7 , 1 , 6 ,
9 , 12 , 4 , 6 ]
x = 8
n = len (arr)
presum = [ 0 ] * n
MakePreSum(arr, presum, n)
print (BinaryLifting(presum, n, x))
|
C#
using System;
class GFG
{
static void MakePreSum( int []arr,
int []presum, int n)
{
presum[0] = arr[0];
for ( int i = 1; i < n; i++)
presum[i] = presum[i - 1] + arr[i];
}
static int BinaryLifting( int []presum,
int n, int x)
{
int pos = 0;
int LOGN = ( int )Math.Log(n);
if (x <= presum[0])
return 0;
for ( int i = LOGN; i >= 0; i--)
{
if (pos + (1 << i) < n &&
presum[pos + (1 << i)] < x)
{
pos += (1 << i);
}
}
return pos + 1;
}
public static void Main()
{
int []arr = { 2, 5, 7, 1, 6, 9, 12, 4, 6 };
int x = 8;
int n = arr.Length;
int []presum = new int [n];
MakePreSum(arr, presum, n);
Console.WriteLine(BinaryLifting(presum, n, x));
}
}
|
Javascript
<script>
function MakePreSum(arr,presum,n)
{
presum[0] = arr[0];
for (let i = 1; i < n; i++)
presum[i] = presum[i - 1] + arr[i];
}
function BinaryLifting(presum, n,k)
{
let pos = 0;
let LOGN = Math.log(n);
if (x <= presum[0])
return 0;
for (let i = LOGN; i >= 0; i--) {
if (pos + (1 << i) < n &&
presum[pos + (1 << i)] < x) {
pos += (1 << i);
}
}
return pos + 1;
}
let arr=[2, 5, 7, 1, 6, 9, 12, 4, 6];
let x = 8;
let n = arr.length;
let presum = new Array(n);
for (let i=0;i<n;i++)
{
presum[i]=0;
}
MakePreSum(arr, presum, n);
document.write(BinaryLifting(presum, n, x));
</script>
|
Time Complexity: O(N)
Auxiliary Space: O(N)
Share your thoughts in the comments
Please Login to comment...