Difference Array | Range update query in O(1)
You are given an integer array arr[]
and a list of queries. Each query is represented as a list of integers where:
[1, l, r, x]
: Addsx
to all elements fromarr[l]
toarr[r]
(inclusive).[2]
: Prints the current state of the array.
You need to perform the queries in order.
Examples :
Input: arr[] = [10, 5, 20, 40], queries = [ [1, 0, 1, 10], [2], [1, 1, 3, 20], [1, 2, 2, 30], [2] ]
Output: 20 15 20 40
20 35 70 60Explanation: [1, 0, 1, 10]: Adds 10 to
arr[0]
andarr[1]
.
Array becomes[20, 15, 20, 40]
.
- (2): Prints the array:
20 15 20 40
.- [1, 1, 3, 20)]: Adds 20 to
arr[1]
,arr[2]
, andarr[3]
.
Array becomes[20, 35, 40, 60]
.- [1, 2, 2, 30]: Adds 30 to
arr[2]
.
Array becomes[20, 35, 70, 60]
.- (2): Prints the array:
20 35 70 60
.
Table of Content
[Naive Approach] Using loops for each queries - O(n * q) time and O(1) space
A simple solution is to do following :
- update(l, r, x) : Run a loop from l to r and add x to all elements from arr[l] to arr[r]
- printArray() : Simply print arr[].
#include <iostream>
#include <vector>
using namespace std;
void update(vector<int> &arr, int l, int r, int x)
{
for (int i = l; i <= r; i++)
{
arr[i] += x;
}
}
void printArray(const vector<int> &arr)
{
for (int num : arr)
{
cout << num << " ";
}
cout << endl;
}
int main()
{
vector<int> arr = {10, 5, 20, 40};
vector<vector<int>> queries = {{1, 0, 1, 10}, {2}, {1, 1, 3, 20}, {1, 2, 2, 30}, {2}};
for (const auto &query : queries)
{
if (query[0] == 1)
{
// update operation
int l = query[1];
int r = query[2];
int x = query[3];
update(arr, l, r, x);
}
else if (query[0] == 2)
{
// print operation
printArray(arr);
}
}
return 0;
}
import java.util.Arrays;
import java.util.List;
public class GfG{
public static void update(int[] arr, int l, int r,
int x)
{
for (int i = l; i <= r; i++) {
arr[i] += x;
}
}
public static void printArray(int[] arr)
{
for (int num : arr) {
System.out.print(num + " ");
}
System.out.println();
}
public static void main(String[] args)
{
int[] arr = { 10, 5, 20, 40 };
int[][] queries = { { 1, 0, 1, 10 },
{ 2 },
{ 1, 1, 3, 20 },
{ 1, 2, 2, 30 },
{ 2 } };
for (int[] query : queries) {
if (query[0] == 1) {
// update operation
int l = query[1];
int r = query[2];
int x = query[3];
update(arr, l, r, x);
}
else if (query[0] == 2) {
// print operation
printArray(arr);
}
}
}
}
def update(arr, l, r, x):
for i in range(l, r + 1):
arr[i] += x
def print_array(arr):
print(' '.join(map(str, arr)))
if __name__ == '__main__':
arr = [10, 5, 20, 40]
queries = [[1, 0, 1, 10], [2], [1, 1, 3, 20], [1, 2, 2, 30], [2]]
for query in queries:
if query[0] == 1:
# update operation
l, r, x = query[1], query[2], query[3]
update(arr, l, r, x)
elif query[0] == 2:
# print operation
print_array(arr)
using System;
using System.Collections.Generic;
class GfG{
static void Update(int[] arr, int l, int r, int x)
{
for (int i = l; i <= r; i++) {
arr[i] += x;
}
}
static void PrintArray(int[] arr)
{
foreach(int num in arr)
{
Console.Write(num + " ");
}
Console.WriteLine();
}
static void Main()
{
int[] arr = new int[] { 10, 5, 20, 40 };
List<List<int>> queries = new List<List<int>>{
new List<int>{ 1, 0, 1, 10 },
new List<int>{ 2 },
new List<int>{ 1, 1, 3, 20 },
new List<int>{ 1, 2, 2, 30 }, new List<int>{ 2 }
};
foreach(var query in queries)
{
if (query[0] == 1) {
// update operation
int l = query[1];
int r = query[2];
int x = query[3];
Update(arr, l, r, x);
}
else if (query[0] == 2) {
// print operation
PrintArray(arr);
}
}
}
}
function update(arr, l, r, x)
{
for (let i = l; i <= r; i++) {
arr[i] += x;
}
}
function printArray(arr) { console.log(arr.join(" ")); }
const arr = [ 10, 5, 20, 40 ];
const queries = [
[ 1, 0, 1, 10 ], [ 2 ], [ 1, 1, 3, 20 ],
[ 1, 2, 2, 30 ], [ 2 ]
];
queries.forEach(query => {
if (query[0] === 1) {
// update operation
const [_, l, r, x] = query;
update(arr, l, r, x);
}
else if (query[0] === 2) {
// print operation
printArray(arr);
}
});
Output
20 15 20 40 20 35 70 60
Time Complexity: O(n * q), O(n) for each queries
Space Complexity: O(1)
[Expected Approach] Using Difference Array
Difference array d[i] of a given array arr[i] is defined as d[i] = arr[i] - arr[i-1] (for 0 < i < n) and d[0] = arr[0] considering 0 based indexing. Difference array can be used to perform range update queries "l r x" where l is left index, r is right index and x is value to be added and after all queries you can return original array from it. Where update range operations can be performed in O(1) complexity.
- update(l, r, x) : Add x to d[l] and subtract it from d[r+1], i.e., we do d[l] += x, d[r+1] -= x
- printArray() : Do a[0] = d[0] and print it. For rest of the elements, do arr[i] = arr[i-1] + d[i] and print them.
Illustration: Let us understand this with an example arr = [2, 5, 7, 9, 6]. The difference array would be d = [2, 3, 2, 2, -3]. After an update say
update(1, 3, 4)
, we add 4 to index 1 and subtract from index 4, the difference array would become d = [2, 7, 2, 2, -7]. Now to print array, we print 2, 2 + 7 = 9, 9 + 2 = 11, 11 + 2 = 13, 13 + (-7) = 6
#include <iostream>
#include <vector>
using namespace std;
vector<int> initDiffArray(vector<int> &arr)
{
int n = arr.size();
// Initialize difference array with an extra element
vector<int> d(n + 1, 0);
d[0] = arr[0];
for (int i = 1; i < n; i++)
{
d[i] = arr[i] - arr[i - 1];
}
return d;
}
void update(vector<int> &d, int l, int r, int x)
{
d[l] += x;
d[r + 1] -= x;
}
void printArray(vector<int> &arr, vector<int> &d)
{
for (int i = 0; i < arr.size(); i++)
{
if (i == 0)
arr[i] = d[i];
else
arr[i] = d[i] + arr[i - 1];
cout << arr[i] << " ";
}
cout << endl;
}
int main()
{
vector<int> arr{10, 5, 20, 40};
vector<int> d = initDiffArray(arr);
vector<vector<int>> queries = {{1, 0, 1, 10}, {2}, {1, 1, 3, 20}, {1, 2, 2, 30}, {2}};
for (const auto &query : queries)
{
if (query[0] == 1)
{
// If it's an update query: update(l, r, x)
int l = query[1];
int r = query[2];
int x = query[3];
update(d, l, r, x);
}
else if (query[0] == 2)
{
// If it's a print query: printArray()
printArray(arr, d);
}
}
return 0;
}
import java.util.Arrays;
import java.util.List;
import java.util.ArrayList;
public class GfG{
public static int[] initDiffArray(int[] arr) {
int n = arr.length;
int[] d = new int[n + 1];
d[0] = arr[0];
for (int i = 1; i < n; i++) {
d[i] = arr[i] - arr[i - 1];
}
return d;
}
public static void update(int[] d, int l, int r, int x) {
d[l] += x;
d[r + 1] -= x;
}
public static void printArray(int[] arr, int[] d) {
for (int i = 0; i < arr.length; i++) {
if (i == 0)
arr[i] = d[i];
else
arr[i] = d[i] + arr[i - 1];
System.out.print(arr[i] + " ");
}
System.out.println();
}
public static void main(String[] args) {
int[] arr = {10, 5, 20, 40};
int[] d = initDiffArray(arr);
List<int[]> queries = new ArrayList<>();
queries.add(new int[]{1, 0, 1, 10});
queries.add(new int[]{2});
queries.add(new int[]{1, 1, 3, 20});
queries.add(new int[]{1, 2, 2, 30});
queries.add(new int[]{2});
for (int[] query : queries) {
if (query[0] == 1) {
// If it's an update query: update(l, r, x)
int l = query[1];
int r = query[2];
int x = query[3];
update(d, l, r, x);
} else if (query[0] == 2) {
// If it's a print query: printArray()
printArray(arr, d);
}
}
}
}
def init_diff_array(arr):
n = len(arr)
d = [0] * (n + 1)
d[0] = arr[0]
for i in range(1, n):
d[i] = arr[i] - arr[i - 1]
return d
def update(d, l, r, x):
d[l] += x
d[r + 1] -= x
def print_array(arr, d):
for i in range(len(arr)):
if i == 0:
arr[i] = d[i]
else:
arr[i] = d[i] + arr[i - 1]
print(arr[i], end=' ')
print()
if __name__ == '__main__':
arr = [10, 5, 20, 40]
d = init_diff_array(arr)
queries = [[1, 0, 1, 10], [2], [1, 1, 3, 20], [1, 2, 2, 30], [2]]
for query in queries:
if query[0] == 1:
# If it's an update query: update(l, r, x)
l, r, x = query[1], query[2], query[3]
update(d, l, r, x)
elif query[0] == 2:
# If it's a print query: print_array()
print_array(arr, d)
using System;
using System.Collections.Generic;
class GfG{
static int[] InitDiffArray(int[] arr)
{
int n = arr.Length;
int[] d = new int[n + 1];
d[0] = arr[0];
for (int i = 1; i < n; i++) {
d[i] = arr[i] - arr[i - 1];
}
return d;
}
static void Update(int[] d, int l, int r, int x)
{
d[l] += x;
d[r + 1] -= x;
}
static void PrintArray(int[] arr, int[] d)
{
for (int i = 0; i < arr.Length; i++) {
if (i == 0)
arr[i] = d[i];
else
arr[i] = d[i] + arr[i - 1];
Console.Write(arr[i] + " ");
}
Console.WriteLine();
}
static void Main()
{
int[] arr = { 10, 5, 20, 40 };
int[] d = InitDiffArray(arr);
List<int[]> queries = new List<int[]>{
new int[] { 1, 0, 1, 10 }, new int[] { 2 },
new int[] { 1, 1, 3, 20 },
new int[] { 1, 2, 2, 30 }, new int[] { 2 }
};
foreach(var query in queries)
{
if (query[0] == 1) {
// If it's an update query: update(l, r, x)
int l = query[1];
int r = query[2];
int x = query[3];
Update(d, l, r, x);
}
else if (query[0] == 2) {
// If it's a print query: printArray()
PrintArray(arr, d);
}
}
}
}
function initDiffArray(arr)
{
const n = arr.length;
const d = new Array(n + 1).fill(0);
d[0] = arr[0];
for (let i = 1; i < n; i++) {
d[i] = arr[i] - arr[i - 1];
}
return d;
}
function update(d, l, r, x)
{
d[l] += x;
d[r + 1] -= x;
}
function printArray(arr, d)
{
for (let i = 0; i < arr.length; i++) {
if (i === 0)
arr[i] = d[i];
else
arr[i] = d[i] + arr[i - 1];
process.stdout.write(arr[i] + " ");
}
console.log();
}
const arr = [ 10, 5, 20, 40 ];
const d = initDiffArray(arr);
const queries = [
[ 1, 0, 1, 10 ], [ 2 ], [ 1, 1, 3, 20 ],
[ 1, 2, 2, 30 ], [ 2 ]
];
queries.forEach(query => {
if (query[0] === 1) {
// If it's an update query: update(l, r, x)
const l = query[1];
const r = query[2];
const x = query[3];
update(d, l, r, x);
}
else if (query[0] === 2) {
// If it's a print query: printArray()
printArray(arr, d);
}
});
Output:
20 15 20 40
20 35 70 60
Time complexity:
For update here is improved to O(1).
For printArray() still takes O(n) time.
Auxiliary Space: O(n)