Facebook Pixel

396. Rotate Function

Problem Description

You have an integer array nums of length n. The problem asks you to find the maximum value among all possible rotation functions.

A rotation function F(k) is calculated for an array that has been rotated k positions clockwise. When you rotate an array by k positions clockwise, the last k elements move to the front of the array.

For each rotation k, the function F(k) is computed as:

  • F(k) = 0 * arr_k[0] + 1 * arr_k[1] + 2 * arr_k[2] + ... + (n-1) * arr_k[n-1]

Where arr_k is the array after rotating the original nums by k positions.

Example to understand rotations:

  • If nums = [4, 3, 2, 6]
  • arr_0 = [4, 3, 2, 6] (no rotation)
  • arr_1 = [6, 4, 3, 2] (rotated 1 position clockwise)
  • arr_2 = [2, 6, 4, 3] (rotated 2 positions clockwise)
  • arr_3 = [3, 2, 6, 4] (rotated 3 positions clockwise)

Calculating F(k) for each rotation:

  • F(0) = 0*4 + 1*3 + 2*2 + 3*6 = 0 + 3 + 4 + 18 = 25
  • F(1) = 0*6 + 1*4 + 2*3 + 3*2 = 0 + 4 + 6 + 6 = 16
  • F(2) = 0*2 + 1*6 + 2*4 + 3*3 = 0 + 6 + 8 + 9 = 23
  • F(3) = 0*3 + 1*2 + 2*6 + 3*4 = 0 + 2 + 12 + 12 = 26

The task is to return the maximum value among all F(k) where k ranges from 0 to n-1. In the example above, the answer would be 26.

Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

Intuition

The key insight is to find a mathematical relationship between consecutive rotation functions F(k) and F(k+1) rather than computing each one from scratch.

Let's observe what happens when we go from F(k) to F(k+1):

  • When rotating by one more position, the last element of the current array moves to the front
  • Every other element shifts one position to the right, which means their multipliers increase by 1

For example, with nums = [A, B, C, D]:

  • F(0) = 0*A + 1*B + 2*C + 3*D
  • F(1) = 0*D + 1*A + 2*B + 3*C

Notice that when going from F(0) to F(1):

  • Elements A, B, C each get multiplied by a coefficient that's 1 higher
  • Element D goes from being multiplied by 3 to being multiplied by 0

This means: F(1) = F(0) + A + B + C - 3*D

More generally: F(1) = F(0) + (A + B + C + D) - 4*D

This can be written as: F(1) = F(0) + sum(nums) - n * nums[n-1]

For any transition from F(k) to F(k+1): F(k+1) = F(k) + sum(nums) - n * nums[n-k-1]

This pattern holds because:

  1. Adding sum(nums) accounts for increasing each element's coefficient by 1
  2. Subtracting n * nums[n-k-1] corrects for the element that wraps around from position (n-1) to position 0, losing its multiplier of (n-1)

With this recurrence relation, we can compute all F(k) values in O(n) time by:

  1. Computing F(0) directly
  2. Computing the sum of all elements once
  3. Using the formula to derive each subsequent F(k) from the previous one
  4. Tracking the maximum value encountered

Solution Approach

The implementation follows the mathematical relationship we discovered between consecutive rotation functions:

  1. Initialize F(0): First, we calculate F(0) directly using the formula:

    f = sum(i * v for i, v in enumerate(nums))

    This computes 0 * nums[0] + 1 * nums[1] + ... + (n-1) * nums[n-1]

  2. Precompute constants: We store two values that remain constant throughout:

    n, s = len(nums), sum(nums)
    • n: the length of the array
    • s: the sum of all elements in the array
  3. Initialize the answer: Set the initial maximum to F(0):

    ans = f
  4. Iterate through remaining rotations: For each rotation from 1 to n-1, we use the recurrence relation:

    for i in range(1, n):
        f = f + s - n * nums[n - i]
        ans = max(ans, f)

    In each iteration:

    • f = f + s - n * nums[n - i] updates F(i) based on F(i-1)
    • The term nums[n - i] identifies the element that was at the last position in the previous rotation and moves to the front
    • s - n * nums[n - i] represents adding 1 to each element's coefficient (via s) and then correcting for the element that wraps around (via - n * nums[n - i])
    • We update ans with the maximum value seen so far
  5. Return the result: After checking all rotations, return the maximum value found:

    return ans

Time Complexity: O(n) - We compute F(0) in O(n) time and then compute each subsequent F(k) in O(1) time.

Space Complexity: O(1) - We only use a constant amount of extra space for variables f, n, s, and ans.

Ready to land your dream job?

Unlock your dream job with a 5-minute evaluator for a personalized learning plan!

Start Evaluator

Example Walkthrough

Let's walk through the solution with nums = [4, 3, 2, 6].

Step 1: Calculate F(0)

F(0) = 0*4 + 1*3 + 2*2 + 3*6 = 0 + 3 + 4 + 18 = 25

So f = 25

Step 2: Precompute constants

n = 4 (length of array)
s = 4 + 3 + 2 + 6 = 15 (sum of all elements)

Step 3: Initialize answer

ans = 25 (start with F(0))

Step 4: Calculate F(1) using the recurrence relation

When we rotate from position 0 to position 1, the element at index n-1 = 3 (which is 6) moves from the last position to the first position.

Using our formula: F(1) = F(0) + s - n * nums[n-1]

F(1) = 25 + 15 - 4*6
F(1) = 25 + 15 - 24
F(1) = 16

Update: f = 16, ans = max(25, 16) = 25

Step 5: Calculate F(2)

The element at index n-2 = 2 (which is 2) was at the last position in rotation 1, now moves to the front.

Using our formula: F(2) = F(1) + s - n * nums[n-2]

F(2) = 16 + 15 - 4*2
F(2) = 16 + 15 - 8
F(2) = 23

Update: f = 23, ans = max(25, 23) = 25

Step 6: Calculate F(3)

The element at index n-3 = 1 (which is 3) was at the last position in rotation 2, now moves to the front.

Using our formula: F(3) = F(2) + s - n * nums[n-3]

F(3) = 23 + 15 - 4*3
F(3) = 23 + 15 - 12
F(3) = 26

Update: f = 26, ans = max(25, 26) = 26

Step 7: Return the result

return ans = 26

The maximum value among all rotation functions is 26, achieved at rotation k=3.

Solution Implementation

1class Solution:
2    def maxRotateFunction(self, nums: List[int]) -> int:
3        """
4        Find the maximum value of rotation function F(k) for all k from 0 to n-1.
5        F(k) = 0*arr[k] + 1*arr[k+1] + ... + (n-1)*arr[k+n-1]
6        where arr[i] represents the rotated array.
7        """
8        # Calculate initial F(0) = 0*nums[0] + 1*nums[1] + ... + (n-1)*nums[n-1]
9        current_rotation_value = sum(index * value for index, value in enumerate(nums))
10      
11        # Get array length and sum of all elements
12        array_length = len(nums)
13        total_sum = sum(nums)
14      
15        # Initialize maximum with F(0)
16        max_rotation_value = current_rotation_value
17      
18        # Calculate F(1) through F(n-1) using the recurrence relation:
19        # F(k) = F(k-1) + sum(nums) - n * nums[n-k]
20        for rotation in range(1, array_length):
21            # Update current rotation value using the formula
22            # Adding total_sum adds 1 to each element's coefficient
23            # Subtracting n * nums[n-rotation] corrects the last element that wraps to position 0
24            current_rotation_value = current_rotation_value + total_sum - array_length * nums[array_length - rotation]
25          
26            # Track the maximum rotation value found so far
27            max_rotation_value = max(max_rotation_value, current_rotation_value)
28      
29        return max_rotation_value
30
1class Solution {
2    public int maxRotateFunction(int[] nums) {
3        // Initialize the value of F(0) where F(k) = 0*nums[k] + 1*nums[k+1] + ... + (n-1)*nums[k+n-1]
4        int currentFunctionValue = 0;
5      
6        // Sum of all elements in the array
7        int totalSum = 0;
8      
9        // Length of the array
10        int arrayLength = nums.length;
11      
12        // Calculate F(0) and the total sum of all elements
13        for (int i = 0; i < arrayLength; ++i) {
14            currentFunctionValue += i * nums[i];  // F(0) = 0*nums[0] + 1*nums[1] + ... + (n-1)*nums[n-1]
15            totalSum += nums[i];
16        }
17      
18        // Initialize the maximum value with F(0)
19        int maxValue = currentFunctionValue;
20      
21        // Calculate F(1), F(2), ..., F(n-1) using the relationship:
22        // F(k) = F(k-1) + sum - n * nums[n-k]
23        // This formula works because when rotating, all elements shift position by 1,
24        // except the last element which moves to position 0
25        for (int rotation = 1; rotation < arrayLength; ++rotation) {
26            currentFunctionValue = currentFunctionValue + totalSum - arrayLength * nums[arrayLength - rotation];
27            maxValue = Math.max(maxValue, currentFunctionValue);
28        }
29      
30        return maxValue;
31    }
32}
33
1class Solution {
2public:
3    int maxRotateFunction(vector<int>& nums) {
4        // Calculate initial F(0) and sum of all elements
5        int currentFunctionValue = 0;
6        int sumOfAllElements = 0;
7        int arraySize = nums.size();
8      
9        // Initialize F(0) = 0*nums[0] + 1*nums[1] + ... + (n-1)*nums[n-1]
10        // Also calculate the sum of all array elements
11        for (int i = 0; i < arraySize; ++i) {
12            currentFunctionValue += i * nums[i];
13            sumOfAllElements += nums[i];
14        }
15      
16        // Track the maximum function value found
17        int maxFunctionValue = currentFunctionValue;
18      
19        // Calculate F(k) for k = 1 to n-1 using the recurrence relation:
20        // F(k) = F(k-1) + sum - n * nums[n-k]
21        // This relation comes from the observation that rotating right by 1 position
22        // increases all indices by 1 (mod n), except the last element becomes first
23        for (int rotation = 1; rotation < arraySize; ++rotation) {
24            // Update function value using the recurrence relation
25            currentFunctionValue = currentFunctionValue + sumOfAllElements - arraySize * nums[arraySize - rotation];
26          
27            // Update maximum if current value is larger
28            maxFunctionValue = max(maxFunctionValue, currentFunctionValue);
29        }
30      
31        return maxFunctionValue;
32    }
33};
34
1/**
2 * Calculates the maximum value of the rotation function F(k) for all possible rotations
3 * F(k) = 0 * arrk[0] + 1 * arrk[1] + ... + (n-1) * arrk[n-1]
4 * where arrk is the array after rotating k positions clockwise
5 * 
6 * @param nums - Input array of numbers
7 * @returns Maximum value among all rotation functions
8 */
9function maxRotateFunction(nums: number[]): number {
10    const arrayLength: number = nums.length;
11  
12    // Calculate the sum of all elements in the array
13    const totalSum: number = nums.reduce((accumulator, value) => accumulator + value, 0);
14  
15    // Calculate F(0) = 0*nums[0] + 1*nums[1] + ... + (n-1)*nums[n-1]
16    let currentRotationValue: number = nums.reduce((accumulator, value, index) => accumulator + value * index, 0);
17  
18    // Initialize the maximum value with F(0)
19    let maxValue: number = currentRotationValue;
20  
21    // Calculate F(k) for k from 1 to n-1 using the relationship:
22    // F(k) = F(k-1) + totalSum - n * nums[n-k]
23    // This formula is derived from the pattern when rotating the array
24    for (let rotation = 1; rotation < arrayLength; rotation++) {
25        // Update current rotation value using the mathematical relationship
26        // F(k) = F(k-1) - (totalSum - nums[k-1]) + nums[k-1] * (n-1)
27        // Simplified: F(k) = F(k-1) + totalSum - n * nums[n-k]
28        currentRotationValue = currentRotationValue - (totalSum - nums[rotation - 1]) + nums[rotation - 1] * (arrayLength - 1);
29      
30        // Update maximum value if current rotation yields a larger value
31        maxValue = Math.max(maxValue, currentRotationValue);
32    }
33  
34    return maxValue;
35}
36

Time and Space Complexity

Time Complexity: O(n)

The algorithm consists of:

  • Initial calculation of f using list comprehension with enumerate(): O(n)
  • Calculating the sum of all elements s: O(n)
  • A for loop that runs n-1 times: O(n)
    • Inside the loop, each operation (arithmetic and max comparison) takes O(1)

Since these operations are sequential, the overall time complexity is O(n) + O(n) + O(n) = O(n).

Space Complexity: O(1)

The algorithm uses only a constant amount of extra space:

  • Variable f to store the current rotation function value
  • Variables n and s to store the length and sum
  • Variable ans to track the maximum value
  • Loop variable i

All these variables use constant space regardless of the input size, resulting in O(1) space complexity.

Common Pitfalls

1. Incorrect Index in Recurrence Relation

One of the most common mistakes is using the wrong index when identifying which element moves from the last position to the first during rotation.

Incorrect Implementation:

for i in range(1, n):
    f = f + s - n * nums[i]  # Wrong! Uses nums[i] instead of nums[n-i]
    ans = max(ans, f)

Why it's wrong: When rotating by i positions, the element that was at the last position in the (i-1)th rotation and moves to the front is nums[n-i], not nums[i].

Correct Implementation:

for i in range(1, n):
    f = f + s - n * nums[n - i]  # Correct index
    ans = max(ans, f)

2. Misunderstanding Rotation Direction

Another pitfall is confusing the rotation direction. The problem specifies clockwise rotation, meaning the last elements move to the front.

Example of confusion:

  • Original: [4, 3, 2, 6]
  • Rotate 1 clockwise: [6, 4, 3, 2] (last element 6 moves to front)
  • NOT: [3, 2, 6, 4] (this would be counter-clockwise)

3. Integer Overflow in Large Arrays

For very large arrays with large values, the rotation function calculations might overflow in languages with fixed integer sizes.

Solution for overflow-prone languages:

  • Use appropriate data types (e.g., long long in C++)
  • In Python, this isn't an issue due to arbitrary precision integers

4. Off-by-One Errors in Loop Range

Forgetting that we need to check exactly n rotations (from 0 to n-1).

Incorrect:

for i in range(n):  # This would try to calculate F(n), which doesn't exist
    f = f + s - n * nums[n - i - 1]

Correct:

for i in range(1, n):  # Calculates F(1) through F(n-1)
    f = f + s - n * nums[n - i]
Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Tailor Your Study Plan:

A person thinks of a number between 1 and 1000. You may ask any number questions to them, provided that the question can be answered with either "yes" or "no".

What is the minimum number of questions you needed to ask so that you are guaranteed to know the number that the person is thinking?


Recommended Readings

Want a Structured Path to Master System Design Too? Don’t Miss This!

Load More