Photo by Tai's Captures on Unsplash
The Circular Array Rotation Algorithm
"Round and round we go, back to where it all started..."
Konnichiwa (hello) fellow programmers, we're back to our usual algorithm articles!🙂
In this article, I'll be describing how I solved the
Circular Array Rotation
Challenge on HackerRank using Python 3.
This challenge is part of the Implementation
challenges in the Algorithm
section on HackerRank.
If this is your first time reading my data structures and algorithms article, please consider reading more in my Algos in Plain English series.😃
Problem 🎲
John Watson knows of an operation called a right circular rotation on an array of integers. One rotation operation moves the last array element to the first position and shifts all remaining elements right one. To test Sherlock's abilities, Watson provides Sherlock with an array of integers. Sherlock is to perform the rotation operation a number of times then determine the value of the element at a given position.
For each array, perform a number of right circular rotations and return the values of the elements at the given indices.
Example
a = [3, 4, 5]
k = 2
queries = [1, 2]
Here k
is the number of rotations on a
, and queries
holds the list of indices to report. First, we perform the two rotations:
[3, 4, 5] -> [5, 3, 4] -> [4, 5, 3]
Now return the values from the zero-based indices 1 and 2 as indicated in the queries
array.
a[1] = 5
a[2] = 3
Function Description
Complete the circularArrayRotation
function in the editor below.
circularArrayRotation
has the following parameter(s):
- int
a[n]
: the array to rotate - int
k
: the rotation count - int
queries[1]
: the indices to report
Returns
- int[q]: the values in the rotated
a
as requested
Sample Input:
a = [1, 2, 3]
k = 2
queries = [0, 1, 2]
Sample Output:
2
3
1
Explanation:
After the first rotation, the array is [3, 2, 1]. After the second (and final) rotation, the array is [2, 3, 1].
We will call this final state array b = [2, 3, 1]
. For each query, we just have to get the value of b[queries[i]]
.
queries[0] = 0, b[0] = 2
queries[1] = 1, b[1] = 3
queries[2] = 2, b[2] = 1
Check out the original challenge on HackerRank for more info on input constraints and other sample inputs.
Solution 🔎
In plain English, for every 'rotation' of an array, the last element moves to the beginning of the array, while the remaining elements come right after. Finally, we need to get the elements at a given index in an array of indices called queries.
Let's get to it!🤓
Step 1️⃣: Getting the actual number of rotations 🤹🏽♂️.
The challenge constraints tell us that we could go from 1 to 100,000 (10^5) rotations. That's a lot of rotations and by just reading that, your inner 'algorithmic soul' should be screaming avoid time and space complexities.
- The challenge says to return the elements at the given indices provided by the queries at the end of the rotations. This means the total number of rotations is not so much of a concern.
- From the sample input above, you'll notice that you can get back the original array
a
after rotating 3 times. From here, you can conclude you get back the original arraya
aftern
rotations. wheren = length of a
. This means you only want to rotate the elements ina
by the remaining rotations. we'll still call thisk
.
We usen = len(a) k = k % n
%
to handle the repeated rotations explained earlier so we can get the remaining rotations aftera
has been rotated back to its original shape.
Step 2️⃣: Getting the array rotation logic 🤔.
This here is the crux of the challenge. Now we know by how much to actually rotate a
, we need to develop some logic to handle this rotation without actually iterating through all rotations (remember we could get up to 100,000 rotations).
A. Remember, we only need to find the index of elements in a
at the end of k
rotations.
Looking at the sample input again, after k rotations (k = 2
), the starting index of the new array (let's call it result
) will be a[1]
(which is 2)
After k = 2 rotations, the starting index of [result] array is 1, the element a[1], which is 2
a = [1, 2, 3]
result = [2, 3, 1]
Let's consider another array:
After k = 9 rotations, the starting index of [result] array is 3, the element at a[3], which is 7
a = [3, 6, 2, 7, 6, 4]
result = [7, 6, 4, 3, 8, 2]
From this, we can deduce that the starting index of the rotated array, result
after k
rotations is n - k
. We'll call this shift
.
shift = n - k
B. With shift
, we can quickly get the rotated indices for any input array.
Given the queries
(which are also indices), we can then get the new queried elements by adding a query index to our rotated index for a given element. This means:
The elements of
result
can be gotten by:
result = a[(shift + query) % n]
# 'query' is an index from queries.
# '%' handles overflows for when the sum is greater than the length of a.
C. All that's left is to add the get the element for each query index in queries (using our beloved list comprehensions😏).
result = [a[(shift + query) % n] for query in queries]
Here's the full source code:
def circularArrayRotation(a, k, queries):
# Write your code here
n = len(a)
k = k % n
shift = n - k
result =[a[(shift + query) % n] for query in queries]
return result
That's it! Thanks for reading! 🙂
Hope this article helped with understanding this challenge. Happy Coding!👨🏽💻
Nonsocchi🥷🏽