匹配名称与相应的32位无符号整数

时间:2016-07-22 01:25:36

标签: javascript java

考虑以下问题http://potw.quinnftw.com/problem/2015/1/

  

Will最近感到非常孤独。为了帮助自己,他创建了一个约会网站。作为一名计算机科学家,他提出了一种有趣的方法来计算一个人与另一个人的匹配程度。

     

根据输入的信息,Will将创建一个32位无符号整数,作为人员数据的掩码。为了计算一对夫妇之间的兼容性,Will会检查他们有多少相似的比特。匹配越多,匹配越好。人们也必须记住,对立面吸引人。

     

您的目标是设计一种算法,以显示具有最高兼容级别和最低兼容级别的对。

总结中的问题是键入一些整数N,然后输入Nnames的相应32位无符号整数。

目标是设计一种算法,显示具有最高兼容级别和最低兼容级别的对。

您可以在链接中查看详细信息。这不是一个太多的阅读。

考虑样本输入

5 
Danniel 116077289 
Bowman 2316887705 
Cleveland 2186347654 
Marinda 2662238983 
Viviana 3393681530

输出

Bowman Cleveland 
Marinda Viviana

我很难理解这个问题。是否告诉我根据数字的出现进行匹配?基本上我跟踪一个int中有多少个整数在另一个名称int中是相同的?输出是通过将这对名称与最常见的数字一起使用来实现的吗?然后第二对具有最少的常见数字?

任何洞察我如何理解这个问题都会很好。到目前为止,我对它的印象是简单地匹配两个具有最多出​​现次数的名称。然而,32位部分令我感到困惑,我不确定这部分是什么意思。

我想用javascript或java来做这件事,但是一旦我完全明白问题是什么,我就不会认为编码太过分了。

谢谢!

考虑其中一个解决方案http://potw.quinnftw.com/solution/17/

我无法理解的部分是for for循环

public static int getScore(long x, long y) {
        int score = 0;
        for (long i = x ^ y; i > 0; i = i >> 1)
            if (i-1 == (i & (i-1)))
                score++;
        return 32 - score;
    }

我很困惑为什么我在这里使用xOR并且每次迭代循环时潜水2次。

3 个答案:

答案 0 :(得分:3)

如果你仔细阅读了这个问题,这是一个关于"两个32位数有多少相同位的问题。您必须以二进制形式检查数字(您可以查看每个位)并比较代表每个人特征的数字之间的位。

因此,一个人的号码可能会被表示为

01001101110011010011010100101111 

和另一个

01111100010011010011010100010111 

要查看它们的匹配程度,您必须查看在相同对应位置的位同时为01的位中,有多少位具有相同的值。为具有相同值的每个位添加一个匹配分数。

由于这是某种学习练习,我不会只是提供代码,但会指向reference on manipulating bits in Javascript

事实证明,这个问题有多个阶段:

  1. 比较两个人的面具编号并生成匹配分数。
  2. 对于所有可能的用户组合,请计算所有匹配分数。
  3. 找到最高匹配分数,将它们添加到最终结果中,从目前为止的所有匹配分数中删除它们,然后找到下一个最高匹配。重复,直到剩下0或1人。
  4. 我的解决方案的输出(尚未链接,因此OP可以自行解决问题):

    Visually in Binary
    00000110111010110011001011101001 Danniel
    10001010000110001110011010011001 Bowman
    10000010010100010000010010000110 Cleveland
    10011110101011101000101100000111 Marinda
    11001010010001110111100001111010 Viviana
    
    All Comparisons (sorted)
    Bowman,Cleveland:19
    Danniel,Viviana:17
    Danniel,Bowman:16
    Cleveland,Viviana:16
    Danniel,Cleveland:15
    Danniel,Marinda:15
    Bowman,Marinda:15
    Bowman,Viviana:15
    Cleveland,Marinda:14
    Marinda,Viviana:12
    
    Best Matches
    Bowman,Cleveland: 19
    Danniel,Viviana: 17
    

    这里有一个提示,用于比较两个数字中给定的位是否相同:

    var bitmask = 1;      // start with lowest bit
    var num1 = 116077289;
    var num2 = 2316887705;
    if ((num1 & bitmask) === (num2 & bitmask)) {
        // the bit represented by bitmask is the same in both numbers
    }
    

    下一个提示:如果位掩码为2,那么您将比较第二位。如果位掩码为4,则您将第三位8再与第四位16,第五位进行比较,依此类推至第32位。添加计数器,您可以计算匹配的位数。

    这是一个有效的解决方案:

    
    
    // function used to make display prettier
    function zeroPadLeft(str, len) {
        while (str.length < len) {
            str = "0" + str;
        }
        return str;
    }
    
    function compareBits(num1, num2) {
        // score is the number of matching bits
        var score = 0;
        // start with first bit
        var mask = 1;
        // create rotating mask to individually compare each of the lowest 32 bits
        for (var i = 0; i < 32; i++) {
            // if this bit has the same value, increase the score
            if ((num1 & mask) === (num2 & mask)) {
                ++score;
            }
            // advance mask to next bit with shift left operator
            mask = mask << 1;
        }
        return score;
    }
    
    // input data
    var data = [
        {name:"Danniel", value:116077289}, 
        {name:"Bowman", value:2316887705}, 
        {name:"Cleveland", value:2186347654}, 
        {name:"Marinda", value:2662238982}, 
        {name:"Viviana", value:3393681530}
    ];
    
    // show the starting data in binary so we can see a visual representation of the actual bits
    log("<b>Visually in Binary</b>");
    data.forEach(function (item) {
        log(zeroPadLeft(item.value.toString(2), 32) + "  " + item.name);
    });
    
    // record the score of all possible combinations in the scores array of objects
    log("<hr>");
    log("<b>All Comparisons</b>");
    var scores = [];
    for (var j = 0; j < data.length; j++) {
        for (var k = j + 1; k < data.length; k++) {
            var score = compareBits(data[j].value, data[k].value);
            // record the score and two names as an object inserted into an array
            scores.push({
                name1: data[j].name,
                name2: data[k].name,
                score: score
            })
        }
    }
    
    // sort by best score to make it easier to find the highest score
    scores.sort(function (a, b) {
        return b.score - a.score;
    });
    // output sorted scores so we can see them visually
    scores.forEach(function (item) {
        log(item.name1 + "," + item.name2 + ":" + item.score);
    });
    
    // now find the top scores with no person repeated
    log("<hr>");
    log("<b>Best Matches</b>");
    // namesUsed keeps track of which names have already found a high score so we don't use them again
    var namesUsed = {};
    while (scores.length > 0) {
        var bestItem = scores.shift();
        // if either of these names has already been used, then skip this score
        if (namesUsed[bestItem.name1] || namesUsed[bestItem.name2]) {
            continue;
        }
        log(bestItem.name1 + "," + bestItem.name2 + ": " + bestItem.score);
        namesUsed[bestItem.name1] = true;
        namesUsed[bestItem.name2] = true;
    }
    &#13;
    body {font-family: "Courier New";}
    &#13;
    <script src="http://files.the-friend-family.com/log.js"></script>
    &#13;
    &#13;
    &#13;

    比较位的说明

    关键部分是计算两个数字相同的位:

    function compareBits(num1, num2) {
        // score is the number of matching bits
        var score = 0;
        // start with first bit
        var mask = 1;
        // create rotating mask to individually compare each of the lowest 32 bits
        for (var i = 0; i < 32; i++) {
            // if this bit has the same value, increase the score
            if ((num1 & mask) === (num2 & mask)) {
                ++score;
            }
            // advance mask to next bit with shift left operator
            mask = mask << 1;
        }
        return score;
    }
    

    这是我认为最简单的理解实现(不是最快的)。基本上它的作用是定义一个初始值为1的掩码号。当我们使用每个值逻辑和掩码编号时,我们在每个数字中隔离一个位。然后我们可以比较剩余的单个位以查看它们是否相等。如果是这样,请提高分数。然后,将掩模向左移动一个位置,以便我们可以查看下一个位。重复32次,我们比较了32位中的每一位,计算了多少具有相同的值。

    如果你想看看钝操作是如何得到的,这里有一个非常快速的算法Hamming weight implementation

    function countSimilarBitsHamming(num1, num2) {
        // xor sets a bit to 0 if both are the same and 1 if different
        // so if we xor and then negate, we get bits that are the same
        var sameBits = ((~(num1 ^ num2)) & 0xFFFFFFFF) >>> 0;
        sameBits = sameBits - ((sameBits >> 1) & 0x55555555);
        sameBits = (sameBits & 0x33333333) + ((sameBits >> 2) & 0x33333333);
        return (((sameBits + (sameBits >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;
    }
    

    这是一个更慢的实现,但位计数部分是一个简单的字符串计数:

    function countBitsString(num1, num2) {
        // xor sets a bit to 0 if both are the same and 1 if different
        // so if we xor and then negate, we get bits that are the same
        var sameBits = ((~(num1 ^ num2)) & 0xFFFFFFFF) >>> 0;
        var str = sameBits.toString(2).replace(/0/g, "");
        return str.length;
    }
    

    步骤:

    1. num1 XOR num2 - 如果num1和num2中的相应位具有相同的值,则生成一个位设置为0的结果,如果它们的值不同,则生成1
    2. XOR值是我们想要的倒数,所以我们用~运算符来否定它。现在,只要两个数字具有相同的位,我们就有1
    3. 因为否定值超过32位,我们和最大32位值将高位清零。
    4. 然后因为Javascript只处理有符号值,但我们想要无符号值,我们使用了一个零填充右移的技巧,但是0移位值为>>> 0,这将清除签署位。
    5. 现在有一个匹配位列表。
    6. 然后,一个非常简单的计算方法是转换为二进制的字符串表示并删除零。剩下的就是字符串中的1 s,所以只需查看字符串的长度以及字符串中1的位置。

答案 1 :(得分:1)

&#34;位&#34;是&#34;二进制数字&#34;的缩写。因此,32位整数是一个整数,可以使用32位二进制数字表示。一个&#34;未签名&#34;整数不能为负数,因此使用普通二进制存储而不是使用two's complement

在二进制文件中,输入可能更有意义。

Danniel   00000110111010110011001011101001
Bowman    10001010000110001110011010011001
Cleveland 10000010010100010000010010000110
Marinda   10011110101011101000101100000111
Viviana   11001010010001110111100001111010

根据问题,兼容性通过相同位数来衡量。因此,您可以使用按位运算符&。按位AND通过逐位比较来组合两个数字。如果两个位都相同,则会在结果中放置1。如果两个位都不同,则会在结果中放置0

例如,&将Danniel与Bowman进行比较。

Danniel   00000110111010110011001011101001
Bowman    10001010000110001110011010011001

Result:   01110011000011000010101110001111

要找到兼容的情侣,请找到&导致最多 1的情侣。

要找到最少兼容的情侣,请找到&导致最少 1的情侣。

答案 2 :(得分:0)

在打我的头5小时之后

function compareBit(num1,num2)
{

    var mask = 1;
    var count = 0;
    for(var i = 0; i<32;i++)
        {
            if((num1&mask) === (num2&mask))
                {
                    ++count;            
                }

            mask = mask << 1;   
        }
    return count;
}
var obj = [];
var number = prompt("Enter how many names and id's you will put");
for(var i = 0 ; i<number ; i++)
    {
        query = prompt("Enter name then id, you must put one space in between");
        query_result = query.split(" ");
        obj.push({name:query_result[0],value:query_result[1]});      
    }



var scores = [];

for (var a = 0 ; a<obj.length ; a++){
    for(var b = a+1 ; b<obj.length ; b++){
        var score = compareBit(obj[a].value,obj[b].value);
        scores.push({name1:obj[a].name,name2:obj[b].name,score:score})
    }
}
var max = scores.reduce(function(prev,current){
   return (prev.score > current.score)  ? prev : current;
});
var min = scores.reduce(function(prev,current){
   return (prev.score < current.score)  ? prev : current;
});
console.log(max.name1+ " " + max.name2);
console.log(min.name1+ " " + min.name2);