LCR 133. 位 1 的个数
思路:位运算知识
位运算知识:
- 移位操作
- 右移>>:向右移动,左侧空位补0 <=> **向下整除2ⁿ
- 左移>>:向左移动,右侧空位补0 <=> **乘以2ⁿ
- 取余数 n%2 等价于 判断二进制最右位 n&1 (结果为1=>奇数)
(分治法专题的LCR 134. Pow(x, n)也用到该知识点)
public class Solution
{
public int HammingWeight(uint n)
{
int res = 0;
while (n != 0)
{
if ((n & 1) == 1) res++;
n >>= 1;
}
return res;
}
}
LCR 190. 加密运算 ❌
思路:用位运算的知识模拟加法。
- n = 数a^数b:相当于把b的值分一部分到a上就形成了新的数n(1^1=0这里忽略了进位,所以第二步用&来模拟不会对结果造成影响)
- c = 数a&数b<<1:1&1=1,再左移一位(右补零)相当于记录两数相加的进位
以上两步循环直到b=0则相加完成。
(之后回头看,看不懂可以参考图解算法数据结构 - LeetBook - 力扣(LeetCode)全球极客挚爱的技术成长平台)
public class Solution
{
public int EncryptionCalculate(int dataA, int dataB)
{
int n = 0, c = 0;
while (dataB != 0)
{
n = dataA ^ dataB; //无进位和n => 该步骤相当于b的值分了一部分给a
c = (dataA & dataB) << 1; //进位c => & + 左移 相当于进位操作
// 循环运算
dataB = c;
dataA = n;
}
return dataA;
}
}
LCR 177. 撞色搭配 ❌
思路:(看注释,方法来源图解算法数据结构 - LeetBook - 力扣(LeetCode)全球极客挚爱的技术成长平台)
public class Solution
{
public int[] SockCollocation(int[] sockets)
{
int a = 0, b = 0, n = 0, m = 1;
foreach (var num in sockets) // 遍历异或,找出不相同的两个编号(相同两个数异或=0,因此结果是出现一次的数字)
n ^= num;
while
((n & m) == 0) // 循环左移,计算m(两个只出现一次的数字为𝑥,𝑦,由于𝑥≠𝑦,则x和y二进制至少有一位不同(即分别为 0 和 1 ),循环 &+左移 结果==1可以找到第一个不同的位)
m <<= 1;
foreach (var num in sockets) // 根据m&的结果可以将sockets拆分为分别包含x和y的两个子数组。再分别对两子数组遍历执行异或操作,即可得到两个只出现一次的数字x,y。
{
if ((m & num) == 0)
a ^= num;
else
b ^= num;
}
return new int[] { a, b };
}
}
LCR 178. 训练计划 VI ❌
方法一:有限状态机(推荐使用,但暂时没看懂)
方法二:遍历统计(遍历数组,统计每个数的二进制位1出现的次数之和;对每位次数%3,得到的结果为“只出现一次的数字”的各二进制位;使用左移+或运算还原该数字并返回)
public class Solution
{
public int TrainingPlan(int[] actions)
{
int[] counts = new int[32];
for (int i = 0; i < actions.Length; i++)
{
for (int j = 0; j < 32; j++)
{
counts[j] += actions[i] & 1; // 更新第 i 位 1 的个数之和
actions[i] >>= 1;
}
}
int res = 0;
for (int i = 31; i >= 0; i--)
{
res <<= 1;
res |= counts[i] % 3; // 恢复第 i 位
}
return res;
}
}