2016-06-23 95 views
3

好的,這是我從CodeEval中挑戰的挑戰。我必須從以標準方式格式化的文件讀取數字,它在每行(x,n)上有一對由逗號分隔的數字。我必須讀取這些值並對它們進行處理,然後打印n的最小倍數,它大於或等於x,其中n是2的冪。從文件中讀取一對數字並處理它們的快速和低內存消耗方式?

確切要求:給定數字x和n ,其中n是2的冪,打印出大於或等於x的n的最小倍數。不要使用除法或模數運算符。

我已經想出了一些解決方案,但他們都不滿足電腦的條件讓我通過挑戰。我只得到部分完成,分數從30到80(從100)不等。

我假設我的解決方案沒有通過速度,但更可能是內存使用要求。

如果有人能夠啓發我,並提供更好,更有效的解決方案,我將不勝感激。

這裏是我的兩個解決方案:

 var filePath = @"C:\Users\myfile.txt"; 

     int x; 
     int n; 

     using (var reader = new StreamReader(filePath)) 
     { 
      string numsFile = string.Empty; 
      while ((numsFile = reader.ReadLine()) != null) 
      { 
       var nums = numsFile.Split(',').ToArray(); 
       x = int.Parse(nums[0]); 
       n = int.Parse(nums[1]); 

       Console.WriteLine(DangleNumbers(x, n)); 
      } 
     } 

< < < >>>

 var fileNums = File.ReadAllLines(filePath); 

     foreach (var line in fileNums) 
     { 
      var nums = line.Split(',').ToArray(); 

      x = int.Parse(nums[0]); 
      n = int.Parse(nums[1]); 

      Console.WriteLine(DangleNumbers(x, n)); 
     } 

方法來檢查數字

public static int DangleNumbers(int x, int n) 
    { 
     int m = 2; 
     while ((n * m) < x) 
     { 
      m += 2; 
     } 

     return m * n; 
    } 

我是相當新的C#和編搗毀,但這兩種方式,我發現從我嘗試過的其他幾個人得到最好的分數。我認爲在每次迭代中創建一個新的string都不太理想,我也不知道如何使用StringBuilder並從中獲取值爲Int

任何正確的方向指針將不勝感激,因爲我真的想通過這個挑戰。

+0

你爲什麼要做m + = 2?如果x是14,n是5,你不想打印出來15,而不是這個函數提供的20?可能只是因爲程序錯誤而導致你的分數不好? – Chris

+2

1.在循環之外創建儘可能多的變量爲什麼在每一輪創建它們,當你可以簡單地重新設置它們的值? 2.「DangleNumbers」功能也一樣。T這裏不需要每次都創建相同的'm',只需將其設置爲全局只讀整數,因爲您需要它的常量值。 +你只需要'm ++',這樣就可以檢查所有後續的乘數,而不是每次跳過2。 –

+0

爲什麼你要將m加2並從m = 2開始? – Adwaenyth

回答

1

n即大於或等於x的最小倍數是可能的:

if(x <= n) 
{ 
    return n; 
} 
else 
{ 
    return x % n == 0 ? x : (x/n + 1) * n; 
} 

隨着x和n是整數,x的結果/ n將被截斷(或有效地向下舍入) 。因此大於x的倍數是n的倍數(x/n + 1)* n

由於您錯過了要求,所以模數版本是最明顯的選擇。儘管你的方法仍然錯誤。 m = 2不會導致返回的最小值,但如果n已經大於x,它實際上可以是最小值的兩倍。

X = 7,N = 8將獲得您而不是16 8.

此外加入2至m將導致類似的問題。

x = 5,n = 2會讓你8而不是6。

使用下面的方法來代替:

public static int DangleNumbers(int x, int n) 
{ 
    int result = n; 
    while(result < x) 
     result += n; 
    return result; 
} 

仍然能夠開始至少右邊根據(現在)進行了優化,但表示的約束。

+0

我已經更新了要求。我沒有提供完整的約束列表。我不允許使用模數或分數運算符。 –

+0

您好,先生,值得一杯啤酒!謝謝!我想我從來沒有足夠好地測試過這個方法,並且在我得到了一些好的樣本並且使用我的方法通過了他們的輸出測試後,我將所有的注意力集中在IO和字符串操作上。 –

+2

雖然這仍然不處理int溢出,所以如果該列表包含大整數值,您必須小心。 – Adwaenyth

0

我試圖改進你的一些建議,並採取變量的循環以外的變量和解決方案,這是多餘的ToArray()調用的解決方案。

static void Main(string[] args) 
    { 

     var filePath = @"C:\Users\sorin\Desktop\sorvas.txt"; 

     int x; 
     int n; 
     string[] nums; 

     using (var reader = new StreamReader(filePath)) 
     { 
      string numsFile = string.Empty; 
      while ((numsFile = reader.ReadLine()) != null) 
      { 
       nums = numsFile.Split(','); 
       x = int.Parse(nums[0]); 
       n = int.Parse(nums[1]); 

       Console.WriteLine(DangleNumbers(x, n)); 
      } 
     } 

    } 


    public static int DangleNumbers(int x, int n) 
    { 
     int m = 2; 
     while ((n * m) < x) 
     { 
      m += 2; 
     } 

     return m * n; 
    } 

所以它看起來像這樣。問題是,即使現在這些數字有所改善,我的分數也較低。

enter image description here

或許它自己的系統惹的禍?

0

使用逐行讀取(而不是讀取所有行)的第一個選項顯然會使用較少的內存(除非可能在文件很小的情況下(例如「1,1」),在這種情況下讀取器的開銷可能會導致問題,但在這一點上使用的內存可能是無關緊要的

同樣地聲明循環外的變量通常更好,但在這種情況下,因爲對象是值類型我不確定它使有區別

最後,做你的DangleNumbers方法最有效的方法可能是使用按位邏輯運算符和事實上n總是2的冪。這是我的嘗試:

public static int DangleNumbers3(int x, int n) 
{ 
    return ((x-1) & ~(n-1))+n; 
} 

本質上它依賴於這樣一個事實,即在二進制中,n的冪總是1後跟0或更多的零。因此,n的倍數總是以相同數量的零結束。所以如果n之後有M個零,那麼你可以採用x的二進制形式,如果它已經以M個零結尾,那麼你有你的答案。否則,你將零的最後M個數字在哪個點你有n的倍數在x下,然後你加1。

在代碼~(n-1)是一個位掩碼,在末尾有M個零位,都是1.因此,當你用一個數字和它並且它將把尾數字清零。我將此應用於(x-1)以避免必須檢查它是否已經是答案並且有特殊情況。

重要的是要注意,這隻適用於n的特殊形式作爲2的冪。這種方法避免了任何循環的需要,因此應該運行得更快(它總共有五個操作並且沒有分支與其他循環方法相比,它們往往至少有一個操作和每個循環的比較。

相關問題