给定两个32位数字,N和M,以及两个位,i和j。写一个方法来设置i和j之间的所有位在N中等于M(例如,M变成N的子串,位于i并从j开始)
实施例
Given N=(10000000000)2, M=(10101)2, i=2, j=6
return N=(10001010100)2
这是我的代码:
class Solution {
/**
*@param n, m: Two integer
*@param i, j: Two bit positions
*return: An integer
*/
public int updateBits(int n, int m, int i, int j) {
n = clearbits(n,i,j);
m = m<<i;
return m|n;
}
public static int clearbits(int n, int i, int j){
//& with 0
long allones = ~0;
long left = allones << (j);
long right = ((1<<i) - 1);
long mask = left | right;
return (int) mask & n;
}}
问题是输入[-123,45,21,26]
预期输出为-37748859
,代码提供输出-123
更新:更改clearbits后处理整数溢出。它无法进行以下输入 输入 [-521,0,31,31] 产量 -521 预期 2147483127
答案 0 :(得分:3)
你真正需要的是:
public int updateBits(int n, int m, int i, int j) {
int mask = ((int)((1L<<(j-i+1))-1))<<(i);
return (n&~mask)|((m<<i)&mask);
}
请注意,出于调试目的,您可以使用以下方法打印出位字符串:
System.out.println(Integer.toBinaryString(mask));
基本上我需要创建一个与i
和j
之间的位位置匹配的掩码。现在假设我想在位置3和5之间进行掩码,我基本上想要生成一个如下所示的掩码:
0000111000
我可以先尝试生成这个:
0000000111
将i
位置向左移动。这个值+ 1
给了我:
0000001000
哪个是1 << (j-i+1)
,并且在(1 << (j-i+1))-1
中减去一个给我的面具我还需要进一步左移i
,所以我得到了掩码:
((1<<(j-i+1))-1)<<(i)
使用(n&~mask)
完成n上的清除位。
我无法直接屏蔽m
中的位,因为我仍然需要左移它,以便它匹配要替换的位串的位置。转移后,我可以使用((m<<i)&mask)
进行掩码。请注意,如果用户确保m适合掩码,则可能不需要屏蔽m
。
现在把两个术语放在一起,你就得到了答案!
return (n&~mask)|((m<<i)&mask);
或者没有屏蔽m
,您可以一步完成:
return (n&~(((int)((1L<<(j-i+1))-1))<<(i)))|(m<<i);
更新:
您可以采用稍微不同的方法,在此处构建蒙版的左侧和右侧,并将两者一起添加。好方法。但是,我注意到的一个错误是:左边不应该是allones << (j+i)
而只是allones << (j+1)
(加上一个,而不是加i
)。
我们还需要再次关注溢出:
int left = (int)(((long)allones) << (j+1));