问题描述:给定一个数组,将数组中的元素向右移动 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();
}
总结:个人最推崇的解法是解法一,题目不算难,但需要理清思路,然后具体写代码也可能会有问题。