import java.util.Arrays;
/**
* Rotate an array of n elements to the right by k steps
* For example, with n = 7 and k = 3,
* the array [1,2,3,4,5,6,7] is rotated to [5,6,7,1,2,3,4].
*
* Note:
* Try to come up as many solutions as you can, there are at least 3 different
* ways to solve this problem.
*
* Hint:
* Could you do it in-place with O(1) extra space?
*
* Related problem:
* Reverse Words in a String II
*
* Tags: Array
*/
class RotateArray {
public static void main(String[] args) {
RotateArray r = new RotateArray();
int[] nums = {1, 2, 3, 4, 5, 6, 7};
int k = 3;
r.rotate(nums, k);
System.out.println(Arrays.toString(nums));
int[] nums2 = {1, 2, 3, 4, 5, 6};
int k2 = 2;
r.rotate(nums2, k2);
System.out.println(Arrays.toString(nums2));
int[] nums3 = {1, 2};
int k3 = 2;
r.rotate(nums3, k3);
System.out.println(Arrays.toString(nums3));
}
/**
* O(n) Time, O(1) Space
* Build a full circle of rotation
* Start from current index and repeat exactly "length of array" times
* 1. Calculate new index which is current index move k steps forward
* If move out of range, just start from beginning again
* newIdx = (curIdx + k ) % len
* 2. Circle can be the same, for example, n = 6, k = 2
* Index will be 0, 2, 4, 0, 2, 4
* So save the start index of the circle
* If start from there again, move one step forward
*/
public void rotate(int[] nums, int k) {
if (nums == null || nums.length == 0) return;
if (nums.length == 1 || k == 0 || k == nums.length) return; // special cases
int len = nums.length;
k %= len;
int idx = 0;
int tmp = nums[idx]; // the number to write to new index
int tmp2; // save the number at new index
for (int i = 0, j = 0; i < len; i++) { // j is the start index of current circle
idx = (idx + k) % len;
tmp2 = nums[idx];
nums[idx] = tmp; // write to new index
tmp = tmp2; // next write
if (idx == j) { // circle ends
idx = ++j; // move to next circle
tmp = nums[idx];
}
}
}
}