Rotate Arrays with Python: Comprehensive LeetCode 189 Solution for Tech Interview Preparation

Efficient In-Place Array Rotation in Python | LeetCode Solution Explained

Introduction

Rotating an array is a fundamental algorithm problem, and one commonly asked in coding interviews. The problem is straightforward: given an integer array nums, you need to rotate the array to the right by k steps, where k is a non-negative integer. In this blog, we will go over the problem in detail and explore three different ways to solve it, with a focus on an efficient, in-place solution with O(1) extra space.

Let’s dive deep into the problem, discuss a few possible approaches, and finally arrive at the optimal solution.


Problem Statement

We are given the following:

  • An integer array nums of length n (1 <= n <= 10^5).

  • A non-negative integer k (0 <= k <= 10^5).

We need to rotate the array to the right by k steps.

Example 1:

  • Input: nums = [1, 2, 3, 4, 5, 6, 7], k = 3

  • Output: [5, 6, 7, 1, 2, 3, 4]

Example 2:

  • Input: nums = [-1, -100, 3, 99], k = 2

  • Output: [3, 99, -1, -100]

The challenge here is to rotate the array in a way that minimizes both time complexity and space usage.

Approach 1: Naive Solution

The most intuitive solution is a brute force approach where we rotate the array by one position at a time k times. However, this approach has a time complexity of O(n * k) and would not work efficiently for large arrays (when both n and k are near their maximum limits).

Approach 2: Using Extra Space (O(n) Space Complexity)

One simple way to solve this problem is by creating a new array and copying the elements in the rotated order. This would reduce the time complexity to O(n), but the space complexity would increase to O(n) because we would need to store the rotated array separately.

Here’s the basic idea for this approach:

  1. Create a new array result of the same size as nums.

  2. For each element in the original array, calculate its new position in the rotated array.

  3. Copy the elements to their new positions.

#class Solution: uncomment if pasting in leetcode
    def rotate(self, nums, k):
        n = len(nums)
        k = k % n  # Handle cases where k is larger than n
        result = [0] * n

        # Rotate the elements and store them in the result array
        for i in range(n):
            new_position = (i + k) % n
            result[new_position] = nums[i]

        # Copy result back to nums
        nums[:] = result
  • Time Complexity: O(n) because we iterate through the array once.

  • Space Complexity: O(n) because we use a separate array to store the rotated elements.

While this solution works, it does not meet the requirement to solve the problem using O(1) extra space. Let's move on to more efficient solutions.


Approach 3: Optimal In-Place Solution with O(1) Extra Space

To achieve O(1) extra space while maintaining O(n) time complexity, we can leverage the concept of array reversal. The idea is based on the observation that:

  • Rotating an array to the right by k steps can be achieved by reversing different parts of the array.

Steps for In-Place Array Rotation

  1. Reverse the entire array: This step puts the last k elements at the front, but in reverse order.

  2. Reverse the first k elements: This will put the last k elements in the correct order.

  3. Reverse the remaining n-k elements: This puts the first n-k elements in the correct order.

Implementation

#class Solution: uncomment if pasting in leetcode
def rotate(nums, k):
    n = len(nums)
    k = k % n  # Handle cases where k is greater than n

    # Step 1: Reverse the entire array
    nums.reverse()

    # Step 2: Reverse the first k elements and Reverse the remaining n-k elements
       nums[:]=nums[-k:]+nums[:-k]

Explanation of Each Step

  1. Reversing the entire array:

    • This step transforms the array from [1, 2, 3, 4, 5, 6, 7] to [7, 6, 5, 4, 3, 2, 1].

    • At this point, the last k elements have been moved to the front, but in reverse order.

  2. Reversing the first k elements:

    • We now reverse the first k elements, so [7, 6, 5] becomes [5, 6, 7].

    • The array now looks like: [5, 6, 7, 4, 3, 2, 1].

  3. Reversing the remaining n-k elements:

    • Finally, reverse the remaining n-k elements, [4, 3, 2, 1], to get [1, 2, 3, 4].

    • The final rotated array is [5, 6, 7, 1, 2, 3, 4].

Time and Space Complexity

  • Time Complexity: O(n) because reversing the array and the slices takes linear time.

  • Space Complexity: O(1) because we are modifying the array in place without using any extra space.


Why This Solution Works

The reason the reversal method works is that reversing the array changes the order of elements such that the last k elements are placed at the front. After that, by reversing the individual segments, we restore the correct order for both parts of the array, resulting in the rotated array.

This solution not only meets the space constraint of O(1) but also runs efficiently with O(n) time complexity, making it optimal for large arrays.


Edge Cases to Consider

  1. When k is 0:

    • If k is zero, the array remains unchanged. This is handled by the modulo operation k = k % n.
  2. When k is greater than the length of the array:

    • By taking k = k % n, we ensure that the number of rotations is always within the bounds of the array length, so no extra work is needed for large k.
  3. When nums has only one element:

    • A single-element array is trivially rotated by any number of steps, as it remains unchanged.

Conclusion

Array rotation is a common problem, and this blog post has explored different methods to rotate an array to the right by k steps. We started with a naive approach that uses extra space, then moved on to the optimal in-place solution with O(1) extra space, using array reversal. This final solution is efficient, simple, and meets the constraints of the problem.

By understanding this method, you can solve the array rotation problem in interviews or competitive programming challenges with ease.


Further Reading

  1. Left Rotation: The same technique can be adapted for rotating an array to the left. The concept remains similar, but the slices would be handled differently.

  2. Circular Array Manipulation: Array rotation is just one example of circular array manipulation, which has many applications in problems like scheduling or sliding window algorithms.

Happy coding!