eBook – Guide Spring Cloud – NPI EA (cat=Spring Cloud)
announcement - icon

Let's get started with a Microservice Architecture with Spring Cloud:

>> Join Pro and download the eBook

eBook – Mockito – NPI EA (tag = Mockito)
announcement - icon

Mocking is an essential part of unit testing, and the Mockito library makes it easy to write clean and intuitive unit tests for your Java code.

Get started with mocking and improve your application tests using our Mockito guide:

Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Reactive – NPI EA (cat=Reactive)
announcement - icon

Spring 5 added support for reactive programming with the Spring WebFlux module, which has been improved upon ever since. Get started with the Reactor project basics and reactive programming in Spring Boot:

>> Join Pro and download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Jackson – NPI EA (cat=Jackson)
announcement - icon

Do JSON right with Jackson

Download the E-book

eBook – HTTP Client – NPI EA (cat=Http Client-Side)
announcement - icon

Get the most out of the Apache HTTP Client

Download the E-book

eBook – Maven – NPI EA (cat = Maven)
announcement - icon

Get Started with Apache Maven:

Download the E-book

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

eBook – RwS – NPI EA (cat=Spring MVC)
announcement - icon

Building a REST API with Spring?

Download the E-book

Course – LS – NPI EA (cat=Jackson)
announcement - icon

Get started with Spring and Spring Boot, through the Learn Spring course:

>> LEARN SPRING
Course – RWSB – NPI EA (cat=REST)
announcement - icon

Explore Spring Boot 3 and Spring 6 in-depth through building a full REST API with the framework:

>> The New “REST With Spring Boot”

Course – LSS – NPI EA (cat=Spring Security)
announcement - icon

Yes, Spring Security can be complex, from the more advanced functionality within the Core to the deep OAuth support in the framework.

I built the security material as two full courses - Core and OAuth, to get practical with these more complex scenarios. We explore when and how to use each feature and code through it on the backing project.

You can explore the course here:

>> Learn Spring Security

Course – LSD – NPI EA (tag=Spring Data JPA)
announcement - icon

Spring Data JPA is a great way to handle the complexity of JPA with the powerful simplicity of Spring Boot.

Get started with Spring Data JPA through the guided reference course:

>> CHECK OUT THE COURSE

Partner – Moderne – NPI EA (cat=Spring Boot)
announcement - icon

Refactor Java code safely — and automatically — with OpenRewrite.

Refactoring big codebases by hand is slow, risky, and easy to put off. That’s where OpenRewrite comes in. The open-source framework for large-scale, automated code transformations helps teams modernize safely and consistently.

Each month, the creators and maintainers of OpenRewrite at Moderne run live, hands-on training sessions — one for newcomers and one for experienced users. You’ll see how recipes work, how to apply them across projects, and how to modernize code with confidence.

Join the next session, bring your questions, and learn how to automate the kind of work that usually eats your sprint time.

Course – LJB – NPI EA (cat = Core Java)
announcement - icon

Code your way through and build up a solid, practical foundation of Java:

>> Learn Java Basics

Partner – LambdaTest – NPI EA (cat= Testing)
announcement - icon

Distributed systems often come with complex challenges such as service-to-service communication, state management, asynchronous messaging, security, and more.

Dapr (Distributed Application Runtime) provides a set of APIs and building blocks to address these challenges, abstracting away infrastructure so we can focus on business logic.

In this tutorial, we'll focus on Dapr's pub/sub API for message brokering. Using its Spring Boot integration, we'll simplify the creation of a loosely coupled, portable, and easily testable pub/sub messaging system:

>> Flexible Pub/Sub Messaging With Spring Boot and Dapr

1. Overview

In this tutorial, we’ll learn some algorithms for array rotation in Java.

We’ll see how to rotate the array elements k times to the right. We’ll also understand how to modify the array in place, although we might use extra space to compute the rotation.

2. Introduction to Array Rotation

Before digging into some solutions, let’s discuss how to start thinking about the algorithm.

We’ll alias the rotation number with the letter k.

2.1. Find the Smallest Rotation

We’ll transform k to the remainder of k divided by the array length, or k modulo (%) of the array length. This allows us to translate a large rotation number to a relatively small one.

2.2. Unit Testing

We might want to test k less than, equal to, and greater than the array length. For example, if we rotate 8 times an array of 6 elements, we’ll need only a 2-cycle rotation.

Similarly, we shouldn’t modify the array if k is equal to the array length. Thus, this is something we need to consider as an edge case.

Finally, we should also check whether the input array isn’t null or k is greater than zero.

2.3. Array and Rotation Testing Variables

We’ll set the following variables:

  • arr as the array to test length 6
  • rotationLtArrayLength = 1 as a rotation less than the array length
  • rotationGtArrayLength = 8 as a rotation greater than the array length
  • ltArrayLengthRotation as the solution for rotationLtArrayLength
  • gtArrayLengthRotation as the solution for rotationGtArrayLength

Let’s look at their initial values:

int[] arr = { 1, 2, 3, 4, 5, 6 };
int rotationLtArrayLength = 1;
int rotationGtArrayLength = arr.length + 2;
int[] ltArrayLengthRotation = { 6, 1, 2, 3, 4, 5 };
int[] gtArrayLengthRotation = { 5, 6, 1, 2, 3, 4 };

2.4. Space and Time Complexity

Nonetheless, we must be confident with time and space complexity concepts to understand the algorithm solution.

3. Brute Force

It’s a common approach to try solving a problem with brute force. This might not be an efficient solution. However, it helps to understand the problem space.

3.1. Algorithm

We solve by rotating in k steps while shifting the elements by one unit in each step.

Let’s have a look at the method:

void bruteForce(int[] arr, int k) {
    // check invalid input
    k %= arr.length;
    int temp;
    int previous;
    for (int i = 0; i < k; i++) {
        previous = arr[arr.length - 1];
        for (int j = 0; j < arr.length; j++) {
            temp = arr[j];
            arr[j] = previous;
            previous = temp;
        }
    }
}

3.2. Code Insight

We iterate over the array length twice with a nested loop. At first, we get a value we want to rotate at index i:

for (int i = 0; i < k; i++) {
    previous = arr[arr.length - 1];
    // nested loop
}

Then, we shift all the elements in the nested for loop by one using a temporary variable.

for (int j = 0; j < arr.length; j++) {
    temp = arr[j];
    arr[j] = previous;
    previous = temp;
}

3.3. Complexity Analysis

  • Time complexity: O(n×k). All the numbers are shifted by one step O(n) for k times.
  • Space complexity: O(1). Constant extra space is used.

3.4. Unit Test

Let’s write a test for the brute force algorithm when k is less than the array length:

@Test
void givenInputArray_whenUseBruteForceRotationLtArrayLength_thenRotateArrayOk() {
    bruteForce(arr, rotationLtArrayLength);
    assertArrayEquals(ltArrayLengthRotation, arr);
}

Likewise, we test k greater than the array length:

@Test
void givenInputArray_whenUseBruteForceRotationGtArrayLength_thenRotateArrayOk() {
    bruteForce(arr, rotationGtArrayLength);
    assertArrayEquals(gtArrayLengthRotation, arr);
}

Finally, let’s test k equal to the array length:

@Test
void givenInputArray_whenUseBruteForceRotationEqArrayLength_thenDoNothing() {
    int[] expected = arr.clone();
    bruteForce(arr, arr.length);
    assertArrayEquals(expected, arr);
}

4. Rotation With Extra Array

We use an extra array to place every element at its correct position. Then, we copy back to the original one.

4.1. Algorithm

To get the rotated position, we’ll find the (i +k ) position module (%) of the array length:

void withExtraArray(int[] arr, int k) {
    // check invalid input

    int[] extraArray = new int[arr.length];
    for (int i = 0; i < arr.length; i++) {
        extraArray[(i + k) % arr.length] = arr[i];
    }
    System.arraycopy(extraArray, 0, arr, 0, arr.length);
}

Notably, although not required, we could return the extra array.

4.2. Code Insight

We move every element from i to the (i + k) % arr.length position in an extra space array.

Finally, we copy it to the original one using System.arraycopy().

4.3. Complexity Analysis

  • Time complexity: O. We have one pass to apply rotation in the new array from which we copy, in another step, over to the original one.
  • Space complexity: O(n). We use another array of the same size to store the rotation.

4.4. Unit Test

Let’s test the rotation with this extra array algorithm when k is less than the array length:

@Test
void givenInputArray_whenUseExtraArrayRotationLtArrayLength_thenRotateArrayOk() {
    withExtraArray(arr, rotationLtArrayLength);
    assertArrayEquals(ltArrayLengthRotation, arr);
}

Likewise, we test k greater than the array length:

@Test
void givenInputArray_whenUseExtraArrayRotationGtArrayLength_thenRotateArrayOk() {
    withExtraArray(arr, rotationGtArrayLength);
    assertArrayEquals(gtArrayLengthRotation, arr);
}

Finally, let’s test k equal to the array length:

@Test
void givenInputArray_whenUseExtraArrayWithRotationEqArrayLength_thenDoNothing() {
    int[] expected = arr.clone();
    withExtraArray(arr, arr.length);
    assertArrayEquals(expected, arr);
}

5. Cyclic Replacements

We could replace an element at its required position every time. However, we’d lose the original value. Therefore, we’ll store it in a temporary variable. Then, we can place the rotated element for n times, where n is the array length.

5.1. Algorithm

We can see the logic of the cyclic replacement in the diagram for k = 2:

Cyclic Replacement

So, we start from the index 0 and do 2-step cycles.

However, there is an issue with this approach. As we might notice, we can return to the initial array position. In that case, we’ll start again as a regular for-loop cycle.

Finally, we’ll keep track of the elements we replaced using a count variable. Our cycle will complete when the count is equal to the array length.

Let’s look at the code:

void cyclicReplacement(int[] arr, int k) {
    // check invalid input

    k = k % arr.length;
    int count = 0;
    for (int start = 0; count < arr.length; start++) {
        int current = start;
        int prev = arr[start];
        do {
            int next = (current + k) % arr.length;
            int temp = arr[next];
            arr[next] = prev;
            prev = temp;
            current = next;
            count++;
        } while (start != current);
    }
}

5.2. Code Insight

There are two parts we need to focus on for this algorithm.

The first one is the outer loop. We iterate for every n/k fraction of elements we replace in a k-step cycle:

for (int start = 0; count < arr.length; start++) {
    int current = start;
    int prev = arr[start];
    do {
        // do loop
    } while (start != current);
}

Therefore, we use a do-while-loop to shift a value by k steps (while saving the replaced value) until we reach the number from which we originally started and go back to the outer loop:

int next = (current + k) % arr.length;
int temp = arr[next];
arr[next] = prev;
prev = temp;
current = next;
count++;

5.3. Complexity Analysis

  • Time complexity: O(n)
  • Space complexity: O(1). Constant extra space is used.

5.4. Unit Test

Let’s test the cyclic replacement array algorithm when k is less than the array length:

@Test
void givenInputArray_whenUseCyclicReplacementRotationLtArrayLength_thenRotateArrayOk() {
    cyclicReplacement(arr, rotationLtArrayLength);
    assertArrayEquals(ltArrayLengthRotation, arr);
}

Likewise, we test k greater than the array length:

@Test
void givenInputArray_whenUseCyclicReplacementRotationGtArrayLength_thenRotateArrayOk() {
    cyclicReplacement(arr, rotationGtArrayLength);
    assertArrayEquals(gtArrayLengthRotation, arr);
}

Finally, let’s test k equal to the array length:

@Test
void givenInputArray_whenUseCyclicReplacementRotationEqArrayLength_thenDoNothing() {
    int[] expected = arr.clone();
    cyclicReplacement(arr, arr.length);
    assertArrayEquals(expected, arr);
}

6. Reverse

This is a simple yet non-trivial algorithm. When we rotate, we might notice that k elements from the back end of the array come to the front, and the rest of the elements from the front shift backward.

6.1. Algorithm

We solve with three steps in which we reverse:

  • All the elements of the array
  • The first k elements
  • The remaining (n-k) elements

Let’s have a look at the code:

void reverse(int[] arr, int k) {
    // check invalid input

    k %= arr.length;
    reverse(arr, 0, arr.length - 1);
    reverse(arr, 0, k - 1);
    reverse(arr, k, arr.length - 1);
}

void reverse(int[] nums, int start, int end) {
    while (start < end) {
        int temp = nums[start];
        nums[start] = nums[end];
        nums[end] = temp;
        start++;
        end--;
    }
}

6.2. Code Insight

We use a helper method similar to brute force’s nested loop. However, we do it in three different steps this time:

We reverse the whole array:

reverse(arr, 0, arr.length - 1);

Then, we reverse the first k elements.

reverse(arr, 0, k - 1);

Finally, we reverse the remaining elements:

reverse(arr, k, arr.length - 1);

Although this seems to introduce redundancy, it’ll allow us to complete the task in linear time.

6.3. Complexity Analysis

  • Time complexity: O(n). n elements are reversed a total of three times.
  • Space complexity: O(1). Constant extra space is used.

6.4. Unit Test

Let’s test the reverse algorithm when k is less than the array length:

@Test
void givenInputArray_whenUseReverseRotationLtArrayLength_thenRotateArrayOk() {
    reverse(arr, rotationLtArrayLength);
    assertArrayEquals(ltArrayLengthRotation, arr);
}

Likewise, we test k greater than the array length:

@Test
void givenInputArray_whenUseReverseRotationGtArrayLength_thenRotateArrayOk() {
    reverse(arr, rotationGtArrayLength);
    assertArrayEquals(gtArrayLengthRotation, arr);
}

Finally, let’s test k equal to the array length:

@Test
void givenInputArray_whenUseReverseRotationEqArrayLength_thenDoNothing() {
    int[] expected = arr.clone();
    reverse(arr, arr.length);
    assertArrayEquals(expected, arr);
}

7. Conclusion

In this article, we saw how to rotate an array by k rotations. We started with brute force and then moved to more complex algorithms like reverse or cyclic replacements with no extra space. We also talked about the time and space complexity. Finally, we discussed unit testing and some edge cases.

The code backing this article is available on GitHub. Once you're logged in as a Baeldung Pro Member, start learning and coding on the project.
Baeldung Pro – NPI EA (cat = Baeldung)
announcement - icon

Baeldung Pro comes with both absolutely No-Ads as well as finally with Dark Mode, for a clean learning experience:

>> Explore a clean Baeldung

Once the early-adopter seats are all used, the price will go up and stay at $33/year.

eBook – HTTP Client – NPI EA (cat=HTTP Client-Side)
announcement - icon

The Apache HTTP Client is a very robust library, suitable for both simple and advanced use cases when testing HTTP endpoints. Check out our guide covering basic request and response handling, as well as security, cookies, timeouts, and more:

>> Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

Course – LS – NPI EA (cat=REST)

announcement - icon

Get started with Spring Boot and with core Spring, through the Learn Spring course:

>> CHECK OUT THE COURSE

Partner – Moderne – NPI EA (tag=Refactoring)
announcement - icon

Modern Java teams move fast — but codebases don’t always keep up. Frameworks change, dependencies drift, and tech debt builds until it starts to drag on delivery. OpenRewrite was built to fix that: an open-source refactoring engine that automates repetitive code changes while keeping developer intent intact.

The monthly training series, led by the creators and maintainers of OpenRewrite at Moderne, walks through real-world migrations and modernization patterns. Whether you’re new to recipes or ready to write your own, you’ll learn practical ways to refactor safely and at scale.

If you’ve ever wished refactoring felt as natural — and as fast — as writing code, this is a good place to start.

eBook Jackson – NPI EA – 3 (cat = Jackson)
2 Comments
Oldest
Newest
Inline Feedbacks
View all comments