Given an array arr[] and a list of queries q[], where each query specifies an operation to perform on the array, implement the class ArrayQueries that supports the following five methods:
- Left: Perform one cyclic left rotation to the given array.
- Right: Perform one cyclic right rotation to the given array.
- Update (int pos, int val): Update the value of index pos by val.
- Inc (int pos): Increment value at index pos by 1.
- Pos (int pos): Return the current value at index pos.
Note: All the queries are performed based on 1-based indexing, although the array itself starts with index 0.
Examples:
Input: arr[] = [1, 2, 3], q[] = ["Left", "Inc 1", "Update 2 6", "Right", "Pos 1", "Pos 2", "Pos 3"]
Output: [1, 3, 6]
Explanation:
Left - Cyclic left rotation -> [2, 3, 1]
Inc 1 - Increment value at position 1 -> [3, 3, 1]
Update 2 6 -Set arr[2] = 6 -> [3, 6, 1]
Right - Cyclic right rotation -> [1, 3, 6]
Pos 1 -> 1
Pos 2 -> 3
Pos 3 -> 6
[Naive Approach] Direct Rotation by Shifting Elements
In the naive method, we physically perform every rotation on the array. For a Left operation, the first element is removed, all remaining elements are shifted one position to the left, and the removed element is placed at the end. For a Right operation, the last element is removed, all elements are shifted one position to the right, and the removed element is placed at the beginning. Since the array is always updated in its actual rotated form, the Update, Inc, and Pos operations are performed directly .
C++
#include <iostream>
#include<vector>
using namespace std;
class ArrayQueries {
private:
int *arr;
int n;
public:
// Constructor: copies the input array
ArrayQueries(int arr[], int n) {
this->n = n;
this->arr = new int[n];
for (int i = 0; i < n; i++) {
this->arr[i] = arr[i];
}
}
// Performs one cyclic left rotation:
void Left() {
if (n == 0) return;
int first = arr[0];
for (int i = 1; i < n; i++) {
arr[i - 1] = arr[i];
}
arr[n - 1] = first;
}
// Performs one cyclic right rotation:
void Right() {
if (n == 0) return;
int last = arr[n - 1];
for (int i = n - 2; i >= 0; i--) {
arr[i + 1] = arr[i];
}
arr[0] = last;
}
// Updates the value at 1-based index pos
void Update(int pos, int val) {
arr[pos - 1] = val;
}
// Increments the value at 1-based index pos by 1
void Inc(int pos) {
arr[pos - 1]++;
}
// Returns the value at 1-based index pos
int Pos(int pos) {
return arr[pos - 1];
}
};
int main() {
int N = 3;
int arr[] = {1, 2, 3};
ArrayQueries aq(arr, N);
int Q = 7;
aq.Left();
aq.Inc(1);
aq.Update(2, 6);
aq.Right();
cout << aq.Pos(1) << " " << aq.Pos(2) << " " << aq.Pos(3);
return 0;
}
Java
import java.util.Arrays;
class ArrayQueries{
private int[] arr;
private int n;
// Constructor: copies the input array
ArrayQueries(int[] arr, int n) {
this.n = n;
this.arr = new int[n];
for (int i = 0; i < n; i++) {
this.arr[i] = arr[i];
}
}
// Performs one cyclic left rotation
void Left() {
if (n == 0) return;
int first = arr[0];
for (int i = 1; i < n; i++) {
arr[i - 1] = arr[i];
}
arr[n - 1] = first;
}
// Performs one cyclic right rotation
void Right() {
if (n == 0) return;
int last = arr[n - 1];
for (int i = n - 2; i >= 0; i--) {
arr[i + 1] = arr[i];
}
arr[0] = last;
}
// Updates the value at 1-based index pos
void Update(int pos, int val) {
arr[pos - 1] = val;
}
// Increments the value at 1-based index pos by 1
void Inc(int pos) {
arr[pos - 1]++;
}
// Returns the value at 1-based index pos
int Pos(int pos) {
return arr[pos - 1];
}
}
public class Main {
public static void main(String[] args) {
int N = 3;
int[] arr = {1, 2, 3};
ArrayQueries aq = new ArrayQueries(arr, N);
int Q = 7;
aq.Left();
aq.Inc(1);
aq.Update(2, 6);
aq.Right();
System.out.println(aq.Pos(1) + " " + aq.Pos(2) + " " + aq.Pos(3));
}
}
Python
class ArrayQueries:
# Constructor: copies the input array
def __init__(self, arr, n):
self.n = n
self.arr = arr[:]
# Performs one cyclic left rotation:
def Left(self):
if self.n == 0:
return
first = self.arr[0]
for i in range(1, self.n):
self.arr[i - 1] = self.arr[i]
self.arr[self.n - 1] = first
# Performs one cyclic right rotation:
def Right(self):
if self.n == 0:
return
last = self.arr[self.n - 1]
for i in range(self.n - 2, -1, -1):
self.arr[i + 1] = self.arr[i]
self.arr[0] = last
# Updates the value at 1-based index pos
def Update(self, pos, val):
self.arr[pos - 1] = val
# Increments the value at 1-based index pos by 1
def Inc(self, pos):
self.arr[pos - 1] += 1
# Returns the value at 1-based index pos
def Pos(self, pos):
return self.arr[pos - 1]
if __name__ == "__main__":
N = 3
arr = [1, 2, 3]
aq = ArrayQueries(arr, N)
Q = 7
aq.Left()
aq.Inc(1)
aq.Update(2, 6)
aq.Right()
print(aq.Pos(1), aq.Pos(2), aq.Pos(3))
C#
using System;
class ArrayQueries {
private int[] arr;
private int n;
// Constructor: copies the input array
public ArrayQueries(int[] arr, int n) {
this.n = n;
this.arr = new int[n];
for (int i = 0; i < n; i++) {
this.arr[i] = arr[i];
}
}
// Performs one cyclic left rotation:
public void Left() {
if (n == 0) return;
int first = arr[0];
for (int i = 1; i < n; i++) {
arr[i - 1] = arr[i];
}
arr[n - 1] = first;
}
// Performs one cyclic right rotation:
public void Right() {
if (n == 0) return;
int last = arr[n - 1];
for (int i = n - 2; i >= 0; i--) {
arr[i + 1] = arr[i];
}
arr[0] = last;
}
// Updates the value at 1-based index pos
public void Update(int pos, int val) {
arr[pos - 1] = val;
}
// Increments the value at 1-based index pos by 1
public void Inc(int pos) {
arr[pos - 1]++;
}
// Returns the value at 1-based index pos
public int Pos(int pos) {
return arr[pos - 1];
}
}
class GFG {
static void Main() {
int N = 3;
int[] arr = {1, 2, 3};
ArrayQueries aq = new ArrayQueries(arr, N);
aq.Left();
aq.Inc(1);
aq.Update(2, 6);
aq.Right();
Console.WriteLine(aq.Pos(1) + " " + aq.Pos(2) + " " + aq.Pos(3));
}
}
JavaScript
class ArrayQueries {
// Constructor: copies the input array
constructor(arr, n) {
this.n = n;
this.arr = new Array(n);
for (let i = 0; i < n; i++) {
this.arr[i] = arr[i];
}
}
// Performs one cyclic left rotation:
Left() {
if (this.n === 0) return;
const first = this.arr[0];
for (let i = 1; i < this.n; i++) {
this.arr[i - 1] = this.arr[i];
}
this.arr[this.n - 1] = first;
}
// Performs one cyclic right rotation:
Right() {
if (this.n === 0) return;
const last = this.arr[this.n - 1];
for (let i = this.n - 2; i >= 0; i--) {
this.arr[i + 1] = this.arr[i];
}
this.arr[0] = last;
}
// Updates the value at 1-based index pos
Update(pos, val) {
this.arr[pos - 1] = val;
}
// Increments the value at 1-based index pos by 1
Inc(pos) {
this.arr[pos - 1]++;
}
// Returns the value at 1-based index pos
Pos(pos) {
return this.arr[pos - 1];
}
}
//Driver Code
const N = 3;
const arr = [1, 2, 3];
const aq = new ArrayQueries(arr, N);
const Q = 7;
aq.Left();
aq.Inc(1);
aq.Update(2, 6);
aq.Right();
console.log(aq.Pos(1) + " " + aq.Pos(2) + " " + aq.Pos(3));
Time Complexity
Left -> O(n)Right -> O(n)Update -> O(1)Inc -> O(1)Pos -> O(1)
Space Complexity: O(n)
[Efficient Approach] Offset-Based Circular Array
In the optimized method, we avoid physically rotating the array. Instead, we maintain a single integer called an offset that represents the net effect of all rotations. The array remains unchanged in memory. When a Left operation is performed, the offset is updated accordingly, and when a Right operation is performed, the offset is updated in the opposite direction, both modulo N. For any query involving a position pos, the actual index in the original array is computed using the offset. After this index mapping, the Update, Inc, and Pos operations become simple direct array accesses.
C++
#include <iostream>
#include<vector>
using namespace std;
class ArrayQueries {
private:
int *arr;
int n;
int shift = 0;
public:
// Constructor: copies the input array
ArrayQueries(int arr[], int n) {
this->n = n;
this->arr = new int[n];
for (int i = 0; i < n; i++) {
this->arr[i] = arr[i];
}
}
// Performs one cyclic left rotation:
// Instead of shifting elements, we only update shift
void Left() {
shift = (shift - 1 + n) % n;
}
// Performs one cyclic right rotation:
// We again only update shift
void Right() {
shift = (shift + 1) % n;
}
// Updates the value at 1-based index pos
// We first convert the logical position to the actual index
void Update(int pos, int val) {
int idx = (pos - 1 - shift + n) % n;
arr[idx] = val;
}
// Increments the value at 1-based index pos by 1
// Logical index is mapped to physical index using shift
void Inc(int pos) {
int idx = (pos - 1 - shift + n) % n;
arr[idx]++;
}
// Returns the value at 1-based index pos
// Logical index is converted to the real array index
int Pos(int pos) {
int idx = (pos - 1 - shift + n) % n;
return arr[idx];
}
};
int main() {
int N = 3;
int arr[] = {1, 2, 3};
ArrayQueries aq(arr, N);
int Q = 7;
aq.Left();
aq.Inc(1);
aq.Update(2, 6);
aq.Right();
cout << aq.Pos(1) << " " << aq.Pos(2) << " " << aq.Pos(3);
return 0;
}
Java
import java.util.Arrays;
class ArrayQueries {
private int[] arr;
private int n;
private int shift = 0;
// Constructor: copies the input array
ArrayQueries(int arr[], int n) {
this.n = n;
this.arr = new int[n];
for (int i = 0; i < n; i++) {
this.arr[i] = arr[i];
}
}
// Performs one cyclic left rotation:
// Instead of shifting elements, we only update shift
void Left() {
shift = (shift - 1 + n) % n;
}
// Performs one cyclic right rotation:
// We again only update shift
void Right() {
shift = (shift + 1) % n;
}
// Updates the value at 1-based index pos
// We first convert the logical position to the actual index
void Update(int pos, int val) {
int idx = (pos - 1 - shift + n) % n;
arr[idx] = val;
}
// Increments the value at 1-based index pos by 1
// Logical index is mapped to physical index using shift
void Inc(int pos) {
int idx = (pos - 1 - shift + n) % n;
arr[idx]++;
}
// Returns the value at 1-based index pos
// Logical index is converted to the real array index
int Pos(int pos) {
int idx = (pos - 1 - shift + n) % n;
return arr[idx];
}
}
public class GFG {
public static void main(String[] args) {
int N = 3;
int[] arr = {1, 2, 3};
ArrayQueries aq = new ArrayQueries(arr, N);
int Q = 7;
aq.Left();
aq.Inc(1);
aq.Update(2, 6);
aq.Right();
System.out.print(aq.Pos(1) + " " + aq.Pos(2) + " " + aq.Pos(3));
}
}
Python
class ArrayQueries:
def __init__(self, arr, n):
self.arr = arr[:]
self.n = n
self.shift = 0
# Performs one cyclic left rotation:
# Instead of shifting elements, we only update shift
def Left(self):
self.shift = (self.shift - 1 + self.n) % self.n
# Performs one cyclic right rotation:
# We again only update shift
def Right(self):
self.shift = (self.shift + 1) % self.n
# Updates the value at 1-based index pos
# We first convert the logical position to the actual index
def Update(self, pos, val):
idx = (pos - 1 - self.shift + self.n) % self.n
self.arr[idx] = val
# Increments the value at 1-based index pos by 1
def Inc(self, pos):
idx = (pos - 1 - self.shift + self.n) % self.n
self.arr[idx] += 1
# Returns the value at 1-based index pos
def Pos(self, pos):
idx = (pos - 1 - self.shift + self.n) % self.n
return self.arr[idx]
if __name__ == "__main__":
N = 3
arr = [1, 2, 3]
aq = ArrayQueries(arr, N)
Q = 7
aq.Left()
aq.Inc(1)
aq.Update(2, 6)
aq.Right()
print(aq.Pos(1), aq.Pos(2), aq.Pos(3))
C#
using System;
class ArrayQueries {
private int[] arr;
private int n;
private int shift = 0;
// Constructor: copies the input array
public ArrayQueries(int[] arr, int n) {
this.n = n;
this.arr = new int[n];
for (int i = 0; i < n; i++) {
this.arr[i] = arr[i];
}
}
// Performs one cyclic left rotation:
// Instead of shifting elements, we only update shift
public void Left() {
shift = (shift - 1 + n) % n;
}
// Performs one cyclic right rotation:
// We again only update shift
public void Right() {
shift = (shift + 1) % n;
}
// Updates the value at 1-based index pos
// We first convert the logical position to the actual index
public void Update(int pos, int val) {
int idx = (pos - 1 - shift + n) % n;
arr[idx] = val;
}
// Increments the value at 1-based index pos by 1
// Logical index is mapped to physical index using shift
public void Inc(int pos) {
int idx = (pos - 1 - shift + n) % n;
arr[idx]++;
}
// Returns the value at 1-based index pos
// Logical index is converted to the real array index
public int Pos(int pos) {
int idx = (pos - 1 - shift + n) % n;
return arr[idx];
}
}
class GFG {
static void Main() {
int N = 3;
int[] arr = {1, 2, 3};
ArrayQueries aq = new ArrayQueries(arr, N);
aq.Left();
aq.Inc(1);
aq.Update(2, 6);
aq.Right();
Console.WriteLine(aq.Pos(1) + " " + aq.Pos(2) + " " + aq.Pos(3));
}
}
JavaScript
class ArrayQueries {
constructor(arr, n) {
this.arr = new Array(n);
this.n = n;
this.shift = 0;
// Constructor: copies the input array
for (let i = 0; i < n; i++) {
this.arr[i] = arr[i];
}
}
// Performs one cyclic left rotation:
// Instead of shifting elements, we only update shift
Left() {
this.shift = (this.shift - 1 + this.n) % this.n;
}
// Performs one cyclic right rotation:
// We again only update shift
Right() {
this.shift = (this.shift + 1) % this.n;
}
// Updates the value at 1-based index pos
// We first convert the logical position to the actual index
Update(pos, val) {
const idx = (pos - 1 - this.shift + this.n) % this.n;
this.arr[idx] = val;
}
// Increments the value at 1-based index pos by 1
// Logical index is mapped to physical index using shift
Inc(pos) {
const idx = (pos - 1 - this.shift + this.n) % this.n;
this.arr[idx]++;
}
// Returns the value at 1-based index pos
// Logical index is converted to the real array index
Pos(pos) {
const idx = (pos - 1 - this.shift + this.n) % this.n;
return this.arr[idx];
}
}
//Driver Code
const N = 3;
const arr = [1, 2, 3];
const aq = new ArrayQueries(arr, N);
const Q = 7;
aq.Left();
aq.Inc(1);
aq.Update(2, 6);
aq.Right();
console.log(aq.Pos(1) + " " + aq.Pos(2) + " " + aq.Pos(3));
Time Complexity
Left -> O(1)Right -> O(1)Update -> O(1)Inc -> O(1)Pos -> O(1)
Space Complexity: O(n)
Explore
DSA Fundamentals
Data Structures
Algorithms
Advanced
Interview Preparation
Practice Problem