【剑指offer|图解|位运算】训练计划VI+撞色搭配


个人主页:聆风吟
系列专栏:数据结构、剑指offer每日一练
少年有梦不应止于心动,更要付诸行动。


文章目录

  • 一. ⛳️训练计划VI(题目难度:中等)
    • 1.1 题目
    • 1.2 示例
    • 1.3 限制
    • 1.4 解题思路
    • 1.5 c++代码
  • 二. ⛳️撞色搭配(题目难度:中等)
    • 2.1 题目
    • 2.2 示例
    • 2.3 限制
    • 2.4 解题思路
    • 2.5 c++代码
  • 全文总结

一. ⛳️训练计划VI(题目难度:中等)

⌈ 在线OJ链接,可以转至此处自行练习 ⌋

1.1 题目

教学过程中,教练示范一次,学员跟做三次。该过程被混乱剪辑后,记录于数组 actions,其中 actions[i] 表示做出该动作的人员编号。请返回教练的编号。

1.2 示例

输入: actions = [5, 7, 5, 5]
输出: 7

1.3 限制

  • 1 <= actions.length <= 10000
  • 1 <= actions[i] < 2^31

1.4 解题思路

  1. 使用 与运算 我们可以获取数字num二进制位的最右边的一位。
    【剑指offer|图解|位运算】训练计划VI+撞色搭配_第1张图片
  2. 配合 右移操作 ,我们可以从低位到高位依次获取num的每一位二进制的值。
  3. 建立一个长度位32的数组,使用上面方法存放所有数字各二进制 1 出现的次数之和。
    【剑指offer|图解|位运算】训练计划VI+撞色搭配_第2张图片
  4. 将 count 各元素对 3 求余,则结果为 “只出现一次的数字” 的各二进制位。
    【剑指offer|图解|位运算】训练计划VI+撞色搭配_第3张图片

  5. 利用 左移或运算,可将数组中的二进制位恢复到数字ret上,然后返回ret即可。
    【剑指offer|图解|位运算】训练计划VI+撞色搭配_第4张图片

1.5 c++代码

class Solution {
public:
    int trainingPlan(vector<int>& actions) {
        int count[32] = { 0 };//用来记录所有数字各二进制 1 出现的次数之和

        //开始统计所有数字各二进制 1 出现的次数之和
        for(int i = 0; i < actions.size(); i++){
            for(int j = 0; j < 32; j++){
                count[j] += (actions[i] >> j) & 1;
            }
        }

        int ret = 0;//记录只出现一次的数字
        int m = 3;
        //将数组中的二进制位恢复到数字ret上
        for(int i = 31; i >= 0; i--){
            ret <<= 1;
            ret |= count[i] % m;
        }

        return ret;
    }
};


二. ⛳️撞色搭配(题目难度:中等)

⌈ 在线OJ链接,可以转至此处自行练习 ⌋

2.1 题目

整数数组 sockets 记录了一个袜子礼盒的颜色分布情况,其中 sockets[i] 表示该袜子的颜色编号。礼盒中除了一款撞色搭配的袜子,每种颜色的袜子均有两只。请设计一个程序,在时间复杂度 O(n),空间复杂度O(1) 内找到这双撞色搭配袜子的两个颜色编号。

2.2 示例

输入: sockets = [4, 5, 2, 4, 6, 6]
输出: [2,5] 或 [5,2]

2.3 限制

  • 2 <= sockets.length <= 10000

2.4 解题思路

拓展知识: 异或运算有个重要的性质,就是两个相同的值异或结果为0,即对任意整数 a 有 a ⊕ a = 0。并且异或运算满足交换律 a ⊕ b = b ⊕ a。

  1. 首先让sockets中的所有元素进行异或,并将结果赋给sum。
    【剑指offer|图解|位运算】训练计划VI+撞色搭配_第5张图片

  2. 根据异或运算定义,若整数 x⊕y 某位二进制位为 1 ,则 x 和 y 的此二进制位一定不同。
    【剑指offer|图解|位运算】训练计划VI+撞色搭配_第6张图片

  3. 因此,我们可以通过与运算从右向左循环判断,获取整数 x⊕y 首位为 1 的位置 ,将其记录于 m 中。
    【剑指offer|图解|位运算】训练计划VI+撞色搭配_第7张图片

  4. 将数组sockets中所有元素二进制均右移m位,并&1判断数字是否相同,即可将数组 sockets 拆分为分别包含 52 的两个子数组,分别对两个子数组进行异或即可得出结果。
    【剑指offer|图解|位运算】训练计划VI+撞色搭配_第8张图片

2.5 c++代码

class Solution {
public:
    vector<int> sockCollocation(vector<int>& sockets) {
        
        int sum = 0;//sockets中的所有元素进行异或,并将结果赋给sum
        for(int i = 0; i < sockets.size(); i++){
            sum ^= sockets[i];
        }

        int pos = 0;//记录sum二进制位最右边一个 1 的位数
        for(int i = 0; i < 32; i++){
            if((sum>>i) & 1){
                pos = i;
                break;
            }
        }

		//将拆分子数组,让子数组进行异或,求出说需要的值。
        int x = 0;
        int y = 0;
        for(int i = 0; i < sockets.size(); i++){
            if((sockets[i] >> pos) & 1)
                x ^= sockets[i];
            else
                y ^= sockets[i];
        }

        return {x, y};
    }
};


全文总结

本文主要讲解:

     今天的干货分享到这里就结束啦!如果觉得文章还可以的话,希望能给个三连支持一下,聆风吟的主页还有很多有趣的文章,欢迎小伙伴们前去点评,您的支持就是作者前进的最大动力!

你可能感兴趣的:(剑指offer每日一练,c++,经验分享,算法,数据结构)