Rotate Array 旋转数组
题目本身容易理解,但要求 O(1),并且想出3种方法。
方法一:数学规律
容易想到使用数学规律计算移动后的下标,但会有一个坑
public void rotate(int[] nums, int k) {
int i = 1, j = 1, base = 0;
while (i <= nums.length) {
int to = k * j % nums.length + base;
if (to == base) {
base += 1;
j = 1;
} else {
int tmp = nums[base];
nums[base] = nums[to];
nums[to] = tmp;
j += 1;
}
i += 1;
}
}
方法二:最大公约数
使用辗转相除法计算 gcd,减少移动的次数
public void rotate(int[] nums, int k) {
k %= nums.length; // 处理 k > 数组长度的情况
int i = 0, gcd = gcd(k, nums.length);
while (i < gcd) {
int tmp = nums[i], j = i;
while (true) {
int s = j + k;
if (s >= nums.length) {
s = s - nums.length;
}
if (s == i) {
break;
}
nums[j] = nums[s];
j = s;
}
nums[j] = tmp;
i += 1;
}
}
public int gcd (int a, int b) {
return b == 0 ? a : gcd(b, a % b);
}
方法三:多次反转
另辟蹊径的方法,感觉适合用在字符串上
public void rotate(int[] nums, int k) {
int n = nums.length;
k %= length;
reverse(nums, 0, n - 1); //先反转全部的元素
reverse(nums, 0, k - 1); //在反转前k个元素
reverse(nums, k, n - 1); //接着反转剩余的
}
//把数组中从[start,end]之间的元素两两交换,也就是反转
public void reverse(int[] nums, int start, int end) {
while (start < end) {
int tmp = nums[start];
nums[start] = nums[end];
nums[end] = tmp;
start += 1;
end -= 1;
}
}