【问题标题】:How to store two Binary Strings in C# and use OR operator如何在 C# 中存储两个二进制字符串并使用 OR 运算符
【发布时间】:2015-11-24 07:47:33
【问题描述】:

输入:

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]);

我得到的编译器错误是:

不能应用运算符'|'到操作数 byte[] 和 byte[]

我也尝试过 BitArray,但这似乎也不对。我尝试了 byte.Parse("10101") ,它只会导致溢出,这对我来说很有意义。

我想要做的是 OR 两个字符串的位,结果将 = 1,也许我需要在 for 循环中移动位,我想也许我可以 OR 两个二进制表示匹配长度的二进制字符串

显然我选择了错误的数据类型 byte[] 来存储我的二进制字符串,我只是没有足够的经验知道如何以正确的数据类型表示这些二进制字符串。

更新

很难选择正确答案,因为有多个正确答案。只是想澄清一下,这个问题有多种解决方案都是很好的答案。

我的问题源于我试图在 HackerRank 上解决的问题:https://www.hackerrank.com/challenges/acm-icpc-team

“给你一个列表,有 N 个参加 ACM-ICPC 世界总决赛的人。每个人要么精通某个主题,要么不精通。找出 2 人团队可以知道的最大主题数. 并找出有多少团队可以知道最大数量的主题。”

感谢我在 Stack Overflow 上获得的帮助,我想出了一个不错的解决方案:

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;
}

【问题讨论】:

  • 您看到的编译器错误/警告是什么?您是否需要将两个二进制字符串存储在一个对象中?为什么不简单地两个变量和| 他们?
  • 将它们解析为整数,然后使用 or 运算符?
  • 错误是不能应用运算符'|'到操作数 byte[] 和 byte[]
  • 我想要做的是 OR 两个字符串的位,结果将 = 1

标签: c#


【解决方案1】:

只有操作数字,没有循环,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);

【讨论】:

  • 这实际上是一个更清洁的解决方案
  • 我厌倦了这个,这很好,除了我实际上试图对每一位进行 OR 并且我可能不得不使用位移
  • 您可以使用 BitConverter 或 Convert 将结果转换回二进制文件。另外,请记住,内存中的类型只是 0 和 1,如果您对两个整数进行 OR 运算,它们将逐位进行 OR 运算,这就是 OR 的工作原理,无论数据类型如何。
  • @BrianOgden,没有得到。是否要输出 OR 的二进制字符串结果?
  • 嘿@kirmir 我更新了我的问题以向您展示我正在处理的问题,请不要为我解决它,我只是想让您看看我要解决的问题,因为它可能会让您感兴趣.
【解决方案2】:

如果要对两个等长的位数组进行二元运算,可以使用Linq,

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

请注意,位操作传统上用于性能至关重要的情况。我不希望此解决方案在批量操作中表现良好,但对于您的特定用例可能已经足够了。


如果您的用例是发现任何结果位是否为“0”,那么您可以使用 linq 的 All 方法。一旦遇到零,这将停止并返回 false。
 bool orResult = g[0].Zip(g[1], (b1, b2) => b1|b2).All(b => b != 0);

【讨论】:

  • @Brigan Ogen - 欢迎您。使用 Linq 是一个有趣的练习,但如果位数少于 32,我会推荐 kimir 的解决方案。
  • 是的,这是一个艰难的决定,但我选择了基米尔的解决方案,因为它还有更多的“幕后”曝光,但再次感谢您的解决方案,一个优雅而有趣的解决方案在行动中看到 Linq 的力量 ;)
【解决方案3】:

对于较小的值(可以转换为整数),您可以使用以下代码。它将二进制值转换为整数,然后应用或运算符|。然后将结果转换回二进制字符串。

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

【讨论】:

  • 您可以使用Convert.ToString(result, 2);,无需创建您的BinaryString 方法。
  • 感谢您的回答,这是一个很好的回答,很高兴了解您的解决方案,我选择了 Kimir 的解决方案,但图片并不容易。
【解决方案4】:

二元或运算符未在类型byte[] 上定义,仅在byte 上定义。

二进制 |运算符是为整数类型和 bool 预定义的。对于整数类型,|计算其操作数的按位或。对于布尔操作数,|计算其操作数的逻辑或;也就是说,当且仅当它的两个操作数都为假时,结果才为假。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-08-13
    • 2017-01-16
    • 1970-01-01
    • 2016-07-06
    • 2012-01-06
    • 1970-01-01
    • 1970-01-01
    • 2015-12-14
    相关资源
    最近更新 更多