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;}}
