2015-11-11 53 views
4

輸入:如何存儲在C#兩個二進制字符串並使用OR運算

10101 
11100 

我想這兩個字符串存儲在數據類型,這樣我可以呼籲兩個| OR操作。

這裏是我的代碼:

 var g = new byte[2][]; 

     g[0] = "10101".Select(item => byte.Parse(item.ToString())).ToArray(); 
     g[1] = "11100".Select(item => byte.Parse(item.ToString())).ToArray(); 

     //won't compile 
     Console.WriteLine(g[0] | g[1]); 

我得到的編譯錯誤是:

無法應用操作 '|'到操作數字節[]和字節[]

我也試過BitArray,但這似乎並不正確。我嘗試了byte.Parse(「10101」),這隻會導致溢出,這對我來說很有意義。

我想要做的是或者兩個字符串的位和結果會= 1,也許我需要通過for循環中的位移動,我想也許我可以只是或二者的二進制表示匹配長度二進制字符串

顯然我選擇了錯誤的數據類型,字節[],來存儲我的二進制字符串,我只是沒有足夠的經驗知道如何代表了正確的數據類型,這些二進制字符串。

UPDATE

這很難選擇一個正確的答案,因爲有多個正確答案。只是想清楚,提出這個問題的多種解決方案是很好的答案。

我的問題導致的一個問題,我試圖解決的HackerRank:https://www.hackerrank.com/challenges/acm-icpc-team

「你給誰出席ACM-ICPC全球總決賽N多人的名單他們每個人要麼以及在精通或者他們不是,找出一個2人團隊可以知道的最大主題數量,並且找出有多少個團隊可以知道最多的主題。

感謝幫助我的堆棧溢出收到我想出了一個不壞的解決方案:

using System; 
using System.Collections.Generic; 
using System.IO; 
using System.Linq; 

class Solution { 
static void Main(String[] args) { 
    var inputArr = Console.ReadLine().Split(' ').Select(item => int.Parse(item)).ToArray(); 
    var n = inputArr[0]; 
    var m = inputArr[1]; 


    var g = new byte[n]; 
    var team = new List<byte>(); 

    var teamsKnowMax = 0; 
    var maxTopics = byte.MinValue >> sizeof(byte) * 8 - m; 

    for(var i = 0; i < n; i++){ 
     g[i] = Convert.ToByte(Console.ReadLine(), 2); 
     maxTopics = maxTopics | g[i]; 
    } 

    for(var j = 0; j < n -1; j++){ 
     for(var k = j+1; k < n; k++){ 
      var or = g[j] | g[k]; 
      if((or & maxTopics) == maxTopics) 
       teamsKnowMax++; 
     } 
    } 

    Console.WriteLine(Convert.ToString(maxTopics,2).ToCharArray().Count(item => item == '1')); 
    Console.WriteLine(teamsKnowMax); 
} 

}

但我沒有考慮到的約束:

2≤N≤500 
1≤M≤500 

所以現在我需要處理一個解決方案,將長二進制字符串分解爲8位塊,如字節區域,分割長二進制字符串,看看是否有效,而不是瀏覽字符串的每個字符。

最初我開始把大的二進制字符串分解成8個段,並處理提醒,如果有的話,這就創建了一個我無法管理的複雜數據結構。通常,解決這些算法是從一開始就選擇正確的數據結構。然後我回到了BitArray,這給了我一些東西,我可以| OR即使二進制字符串非常大。感謝這個鏈接和內容提供商:https://codereview.stackexchange.com/questions/80458/acm-icpc-team-challenge-on-hackerrank-easy

static void Main(String[] args) { 
    var input = Console.ReadLine().Split(' ').Select(item => int.Parse(item)).ToArray(); 
    var N = input[0]; 
    var M = input[1]; 
    var maxTopics = 0; 
    var maxTeams = 0; 
    var bitArray = new BitArray[N]; 

    for(var n = 0; n < N; n++){ 
     bitArray[n] = new BitArray(M); 

     var topics = Console.ReadLine(); 

     for(var m = 0; m < M; m++){ 
      bitArray[n].Set(m, topics[m] == '1'); 
     } 
    } 

    for(int i = 0; i < N -1; i ++){ 
     for(int j = i + 1; j < N; j++){ 
      var tempTopics = BitsOnCount(new BitArray(M).Or(bitArray[i]).Or(bitArray[j])); 

      if (tempTopics > maxTopics){ 
       maxTopics = tempTopics; 
       maxTeams = 1; 
      }else if(tempTopics == maxTopics){ 
       maxTeams++; 
      } 

     } 
    } 

    Console.WriteLine(maxTopics); 
    Console.WriteLine(maxTeams); 
} 

static int BitsOnCount(BitArray bitArray) 
{ 
    var count = 0; 
    foreach (var bit in bitArray) 
    { 
     if ((bool) bit) 
      count++; 
    } 

    return count; 
} 
+0

什麼是你看到的編譯器錯誤/警告?你是否需要將二進制字符串存儲在一個對象中?爲什麼不只是兩個變量和'|'他們? – Tim

+0

將它們解析爲整數,然後使用or運算符? – cubrr

+0

錯誤是無法應用運算符'|'到操作數字節[]和字節[] –

回答

5

該解決方案只處理數字,沒有循環,LINQ等應該是最好的性能。

var str1 = "10101"; 
var str2 = "11100"; 

var num1 = Convert.ToByte(str1, 2); 
var num2 = Convert.ToByte(str2, 2); 
var or = num1 | num2; 

// We need to lookup only that bits, that are in original input values. 
// So, create a mask with the same number of bits. 
var mask = byte.MaxValue >> sizeof(byte) * 8 - Math.Max(str1.Length, str2.Length); 
var result = (or & mask) == mask; 

// True, when all bits after OR are 1, otherwise - False. 
Console.WriteLine(result); 
+0

這實際上是一個更清潔的解決方案 – victor

+0

我厭倦了這一點,這是很好,除非我真的試圖或每個位,我可能不得不使用位移 –

+0

您可以轉換結果回到二進制使用BitConverter或轉換。另外,記住類型在內存中只有0和1,如果你是兩個整數,它們會一點一點地進行或運算,這就是OR的工作原理,不管數據類型如何。 – victor

0

二進制或操作員沒有對byte[]類型定義,只有byte

Binary |運算符是爲整型和布爾值預定義的。對於整數類型,|計算其操作數的按位或。對於bool操作數,|計算其操作數的邏輯或;也就是說,當且僅當它的兩個操作數都是假時,結果纔是錯誤的。

https://msdn.microsoft.com/en-us/library/kxszd0kx.aspx

3

如果你想對位的兩個相等長度的數組進行二進制操作,您可以使用LINQ,

var orResult = g[0].Zip(g[1], (b1, b2) => b1|b2).ToArray(); 

需要注意的是位操作中的情況下傳統上使用性能是至關重要的。我不希望這種解決方案能夠很好地執行批量操作,但對於您的特定用例來說可能已經足夠了。


如果你的用例是發現任何結果位是否爲'0',那麼你可以使用linq的 All方法。這將停止並在遇到零時立即返回錯誤。

bool orResult = g[0].Zip(g[1], (b1, b2) => b1|b2).All(b => b != 0); 
+0

一個非常好的答案,我很感謝@Andrew –

+1

@Brigan Ogen - 您的歡迎。使用Linq是一個有趣的練習,但如果位數小於32,我會推薦kimir的解決方案。 –

+0

是的,這是一個艱難的決定,但我選擇了Kimir的解決方案,因爲它還有一點「底層」曝光,但再次感謝您的解決方案,這是一個優雅的解決方案,是一個有趣的解決方案, Linq;) –

1

對於較小的值(可以轉換爲整數),可以使用下面的代碼。它將二進制值轉換爲整數,然後應用運算符|。結果然後轉換回二進制字符串。

using System; 

public class Program 
{ 
    public static void Main() 
    { 
     var str1 = "10101"; 
     var str2 = "11100"; 
     var mask = str1.Replace('0','1'); 
     int one = Convert.ToInt32(str1, 2); 
     int two = Convert.ToInt32(str2, 2); 
     int maskbit = Convert.ToInt32(mask, 2); 
     int result = (one | two)^maskbit; 

     if (result==0){ 

      Console.WriteLine("All flags set");    
     } 
     else    
     { 
      Console.WriteLine("Not all flags set");    
     } 
    } 
} 
+0

你可以使用'Convert.ToString(result,2);'不需要創建'BinaryString'方法。 – victor

+0

謝謝@victor,我糾正了我的帖子。 – Jaco

+0

感謝您的回答,這是一個很好的答案,並且很高興瞭解您的解決方案,我與Kimir的解決方案一起去了,但這並不容易。 –

相關問題