【问题标题】:c# Hackerrank code terminated due to time out but there is no way to optimize this code further?c# Hackerrank 代码因超时而终止,但没有办法进一步优化此代码?
【发布时间】:2016-11-21 08:42:10
【问题描述】:

我在 c# 中进行了黑客等级挑战,试图将我的一些 c 技能带到 c# 中。现在我知道黑客等级由于超时而杀死程序是出了名的愚蠢(在这种情况下,如果它持续超过 3 秒)。但老实说,我想不出进一步优化这段代码的方法。

以下是说明: https://www.hackerrank.com/challenges/ctci-array-left-rotation

基本上,挑战是在数组内向左移动数字数组一些 x 次。

据我所知,这段代码是尽可能少的,并且仍然可以按照他们的要求进行操作。我认为进一步优化此代码的唯一方法是将约束“if(a[i] > 1000000 || a[i]

对我来说,这实际上是将数组移动 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] + " " );      
        }

}

}

【问题讨论】:

  • 我不想回答这个问题,因为给你做挑战是不公平的,尤其是一个如此简单的挑战。我给你一个提示。您的两个 for 循环在 100000*100000 操作中执行,大约需要 17 分钟。但是你为什么要执行移位呢。你不能告诉哪个元素将移动到第一个位置,哪个到第二个,在 k 移动而不移动 k 次之后?也许你可以输出答案?
  • 这是我第一次尝试优化某些东西。我会看看直接输出一些东西。
  • 谢谢,现在所有的绿色复选标记。我将原始数组写入具有更新位置的新数组。这不是我想要的方式,因为我认为这不是挑战的目标。但是所有的绿色复选标记都没有减少。

标签: c# optimization timeout


【解决方案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));
    }
}

【讨论】:

    【解决方案2】:

    一次洗牌一个值非常慢。没有必要这样做。可以将旋转视为移动 2 个方块 - 旋转点左侧的值以及包括旋转点和右侧的值

    1  2  3  4  5  6  7  8  9
    

    旋转 3 次是

    1. 将 1-3 移至临时变量
    2. 将 4-9 移动到数组的开头
    3. 将 1-3 移动到 4-9 的末尾

    编辑:添加更多细节

    我们想将数组旋转 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 中的约束是问题定义的一部分——它们告诉我们这些值可以/将会做什么,这样我们就不必担心解决更普遍的问题

    例如
    1

    告诉我们这些数字都在标准整数范围内,无需使用longBigInteger。作为解决方案的一部分,我们不需要确认这些。在现实世界的情况下,不同的规则适用,但在这里我们有尽可能多的代码检查值,因为我们已经解决了问题。

    【讨论】:

    • 我不完全明白你的意思。
    【解决方案3】:

    这已经得到解答,但有一个非常快的不同解决方案:

    这个想法是您使用移位的周期性。移动元素n+1 次与移动元素1 时间相同,归结为k % n。 因此,您可以简单地创建一个新数组并将“旧”元素直接移动到正确的位置。请看下面的示例代码:

    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
    

    编辑:为了简单起见,我跳过了检查边界的部分。

    【讨论】:

      【解决方案4】:

      更新的答案。

      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] + " " );      
                  }
      
      
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-02-06
        • 2016-09-10
        • 2018-03-03
        • 1970-01-01
        相关资源
        最近更新 更多