问题描述:给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数。
解法一:将下标为i的元素放在下标i+k处,再将下标i+k处的元素放置在正确位置,以此类推(AC),时间复杂度:O(n),空间复杂度:O(1),代码如下:
private static void Rotate1(int[] nums,int k) { if (k == 0) return; int count = 0; k = k % nums.Length; for(int start=0;count<nums.Length;++start) { int current = start; int pre = nums[start]; do { int next = (current + k) % nums.Length; int temp = nums[next]; nums[next] = pre; pre = temp; ++count; current = next; } while (current != start); } }
解法二:每次往后移一位,执行k次(当数组很大且k较大时时间超出限制),时间复杂度:O(kn),空间复杂度:O(1);代码如下:
private static void Rotate2(int[] nums, int k) { if (k == 0 || nums.Length==1) return; if (k < 0) Console.WriteLine("Input wrong"); int length = nums.Length; int temp, previous; for(int i=0;i<k;++i) { previous = nums[length - 1]; for(int j=0;j<length;++j) { temp = nums[j]; nums[j] = previous; previous = temp; } } }
解法三:将整个数组翻转,再分别翻转前后两个部分(AC),时间复杂度:O(n),空间复杂度:O(1),代码如下:
private static void Rotate3(int[] nums, int k) { if(nums==null || k<0 ) { Console.WriteLine("Input wrong!"); return; } k = k % nums.Length; int end = nums.Length - 1; Reverse(nums, 0, end); Reverse(nums, 0, k - 1); Reverse(nums, k, end); } //翻转 private static void Reverse(int[] nums,int start,int end) { if (nums == null || start < 0 || start > end) { return; } while(start<end) { int temp = nums[end]; nums[end] = nums[start]; nums[start] = temp; ++start; --end; } }
解法四:利用一个额外的数组(leetcode AC),时间复杂度:O(n),空间复杂度:O(n),代码如下:
private static void Rotate4(int[] nums, int k) { if(nums==null || k<0) { Console.WriteLine("Imput wrong!"); return; } int[] a = new int[nums.Length]; for(int i=0;i<nums.Length;++i) { a[(i + k) % nums.Length] = nums[i]; } for(int i=0;i<nums.Length;++i) { nums[i] = a[i]; } }
Main方法如下:
static void Main(string[] args) { int[] nums = { 1, 2, 3, 4, 5, 6 }; Rotate1(nums, 2); for (int i = 0; i < nums.Length; ++i) Console.Write("{0} ", nums[i]); Console.ReadKey(); }总结:个人最推崇的解法是解法一,题目不算难,但需要理清思路,然后具体写代码也可能会有问题。