我在c#中做了一个黑客等级挑战,试图将我的一些技能带到c#。现在我知道黑客级别因为超时而被杀死程序是非常愚蠢的(在这种情况下,如果持续时间超过3秒)。但老实说,我无法想到进一步优化此代码的方法。
以下是说明: https://www.hackerrank.com/challenges/ctci-array-left-rotation
基本上,挑战是在数组内向左移动一个数字数组大约x倍。
据我所知,这段代码尽可能少,但仍可按照要求进行操作。我可以考虑进一步优化这个代码的唯一方法是将约束“if(a [i]> 1000000 || a [i]< 1)”与代码末尾的writeline forloop合并,但是我尝试过,它没有用。
对我而言,这实际上是将数组移动x的最小操作次数。但由于超时,代码在测试用例7和8(满分为8)中失败。我错过了什么吗?
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
class Solution
{
static void Main(String[] args)
{
int i, j;
int temp = 0;
string[] tokens_n = Console.ReadLine().Split(' ');
int n = Convert.ToInt32(tokens_n[0]);
int k = Convert.ToInt32(tokens_n[1]);
string[] a_temp = Console.ReadLine().Split(' ');
int[] a = Array.ConvertAll(a_temp,Int32.Parse);
//constraints
if(n >= 100000 || n < 1 )
{
System.Environment.Exit(1);
}
if(k > n || n < 1 )
{
System.Environment.Exit(1);
}
for(i = 0; i< n; i++)
{
if(a[i] > 1000000 || a[i] < 1 )
{
System.Environment.Exit(1);
}
}
//double for loop. one adjust position by one. then repeat k number of times.
for(j = 0; j<k; j++)
{
for(i = 0; i< n-1; i++)
{
temp = a[i];
a[i] = a[i+1];
a[i+1] = temp;
}
}
//view array
for(i = 0; i< n; i++)
{
Console.Write(a[i] + " " );
}
}
}
答案 0 :(得分:1)
一次一个地移动值非常慢。没有必要这样做。可以将旋转视为移动2个块 - 旋转点左侧的值以及旋转点的右侧和值
1 2 3 4 5 6 7 8 9
旋转3次
编辑:添加更多细节
我们希望将数组旋转3个位置。
将1 2 3移动到临时数组
1 2 3
1 2 3 4 5 6 7 8 9
将4-9移动到数组的开头
1 2 3
4 5 6 7 8 9 7 8 9
将1-3移动到数组的末尾
1 2 3
4 5 6 7 8 9 1 2 3
如果我们创建一个新的目标数组并将所有内容复制到它,我们可以在没有左侧块的临时数组的情况下离开。以下内容通过了问题的所有测试
var result = new int[a.Length];
var block2Length = a.Length - k;
Array.Copy(a, k, result, 0, block2Length);
Array.Copy(a, 0, result, block2Length, k);
Console.WriteLine(string.Join(" ", result.Select(v => v.ToString())));
其他要点
HackerRank中的约束是问题定义的一部分 - 它们告诉我们价值可以/将要做什么,以便我们不必担心解决更普遍的问题
e.g。
1&lt; = a [i]&lt; 10 ^ 6
告诉我们数字将全部在标准整数的范围内,无需使用long
或BigInteger
。作为解决方案的一部分,我们不需要确认这些。在现实世界的情况下,不同的规则适用,但在这里我们有尽可能多的代码检查值,因为我们已经解决了这个问题。
答案 1 :(得分:1)
这已经得到了回答,但有一种不同的解决方案非常快:
这个想法是你使用移位的周期性。移动元素n+1
次与将1
时间移动到k % n
的时间相同。
因此,您可以简单地创建一个新数组并移动&#34; old&#34;元素直接到正确的位置。请参阅以下示例代码:
static void Main(String[] args) {
string[] tokens_n = Console.ReadLine().Split(' ');
int n = Convert.ToInt32(tokens_n[0]);
int k = Convert.ToInt32(tokens_n[1]);
string[] a_temp = Console.ReadLine().Split(' ');
int[] a = Array.ConvertAll(a_temp,Int32.Parse);
// use the periodicity of the shifting creating a shift between 0 and n - 1.
int shifts = k % n;
// Create a new array to hold the elements at their new positions.
int[] newPositions = new int[a.Length];
// You only need to iterate of the array once assigning each element its new position.
for(int i= 0; i < a.Length; ++i)
{
// Here is the magic: (for clarification see table below)
int position = (i - shifts + n)%n;
newPositions[position] = a[i];
}
foreach(var element in newPositions)
Console.Write($"{element} ");
}
一旦你把它写在纸上,这就更直观了。该表可能会打印比数组所包含的值更多的值,以显示数组中的实际位置。
-4 -3 -2 -1 | 0 1 2 3 4 (array indices)
=============================
2 3 4 5 | 1 2 3 4 5 (array contents without shift)
3 4 5 1 | 2 3 4 5 1 (shifted 1 time)
4 5 1 2 | 3 4 5 1 2 (shifted 2 times)
5 1 2 3 | 4 5 1 2 3 (shifted 3 times)
1 2 3 4 | 5 1 2 3 4 (shifted 4 times)
formula: i - k + n
results:
i=0: 0 - 4 + 5 = 1
i=1: 1 - 4 + 5 = 2
i=2: 2 - 4 + 5 = 3
i=3: 3 - 4 + 5 = 4
i=4: 4 - 4 + 5 = 5
i=5: 5 - 4 + 5 = 6 => 0
编辑:为了简单起见,我跳过了部分检查边界。
答案 2 :(得分:1)
我使用了队列机制来实现这一点。这样你就不必进行任何数组复制,只需将字符串旋转到最后。
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
class Solution {
static int[] leftRotation(int[] arr, int rotation) {
Queue<int> queue = new Queue<int>(arr);
for (int i = 0; i < rotation; i++)
{
queue.Enqueue(queue.Dequeue());
}
return queue.ToArray();
}
static void Main(String[] args) {
string[] tokens_n = Console.ReadLine().Split(' ');
int n = Convert.ToInt32(tokens_n[0]);
int d = Convert.ToInt32(tokens_n[1]);
string[] a_temp = Console.ReadLine().Split(' ');
int[] a = Array.ConvertAll(a_temp,Int32.Parse);
int[] result = leftRotation(a, d);
Console.WriteLine(String.Join(" ", result));
}
}
答案 3 :(得分:0)
更新了答案。
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
class Solution
{
static void Main(String[] args)
{
int i, j, z;
string[] tokens_n = Console.ReadLine().Split(' ');
int n = Convert.ToInt32(tokens_n[0]);
int k = Convert.ToInt32(tokens_n[1]);
string[] a_temp = Console.ReadLine().Split(' ');
int[] a = Array.ConvertAll(a_temp,Int32.Parse);
int[] temparray = new int[2*n];
//constraints
if(n >= 100000 || n < 1 )
{
System.Environment.Exit(1);
}
if(k > n || n < 1 )
{
System.Environment.Exit(1);
}
for(i = 0; i< n; i++)
{
if(a[i] > 1000000 || a[i] < 1 )
{
System.Environment.Exit(1);
}
}
for(j = 0; j<n; j++)
{
z = (j-k) %n;
if(z != 0)
{
z= (n+ z) %n;
}
temparray[z] = a[j];
}
//view array
for(i = 0; i< n; i++)
{
Console.Write(temparray[i] + " " );
}
}
}