在我的情况下,奇偶校验定义为:
相邻的0,1排列的数量,使所有0在左边,所有1都在右边。
请注意,不计算1,1的排列和0,0的排列。当排列的数量是偶数时,则奇偶校验被称为偶数,否则它是奇数。
一些例子:
'101'奇数
'1000'奇数
'10011'甚至
'10100'奇数
答案 0 :(得分:3)
首先,请注意,相邻0-1排列的最小数量是inversions的数量:它是0-1对的数量,0表示1的右边。
令( Ki )是所有设置位的排序顺序(即,位等于1)。位置从零开始计数,从右计数(即从低位开始)。然后在 i - 设置位( i 从零开始计数)右侧有 Ki - i 零位。因此,在所有设置位上,反转的总数是 sum(Ki) - sum(i)。
第一部分易于处理。如果 Ki 是偶数,请丢弃它。如果 Ki 为奇数,则切换总和的奇偶校验。因此实际上 sum(Ki)的奇偶校验等于奇数位置中的设置位数的奇偶校验。可以很容易地找到这个数字:首先屏蔽所有偶数位,然后计算设置位数(popcount)。
第二部分也很容易处理。首先,计算您的号码中的设置位数(再次使用popcount)。让它成为 n 。现在 k = 0..n-1 的 k 的总和恰好是(n-1)* n / 2 。请注意,当且仅当数字 n 中的第二位(从此处的1开始计数)被设置时,它才是奇数。因此,只要您获得 n ,您只需要提取其第二位。
以下是C ++中生成的代码:
uint32_t get_inversions_parity(uint32_t x) {
uint32_t bitsCnt = popcount(x);
uint32_t oddCnt = popcount(x & 0xAAAAAAAAU);
return ((bitsCnt >> 1) ^ oddCnt) & 1;
}
如你所见,你只需要一些快速的方法来做popcount。