位运算小手段巧解 操作 + 例题

位运算有好多应用,限于篇幅 懒呐 这里只列举了一部分,整理好再补充

1.交换两个数(不需额外变量)

#include<iostream>
using namespace std;
int main() {
    ios::sync_with_stdio(false);
    int x, y;
    cin>>x>>y;
    x = x ^ y;
    y = x ^ y;
    x = x ^ y;
    cout<<x<<' '<<y"\n";
    return 0;
}

PS:x^x=0; x^0=x;

PPS:其实不借助额外变量还有另一种方法 当然这是题外话

x = x + y;
y = x - y;
x = x - y;

2.判断一个数是否为2的幂次方
如果一个数是2的幂次方,那么这个数的二进制数中有且仅有一个1,其余为0,将这个数减去1得到的值的二进制数1变成0,1之后的0,全部变成1,显然,两数做与运算的结果为0,由这个结论即可判断一个数是否为2的幂次方。代码如下:

int judge(int n){
    return n & (n - 1);
}

PS:128 :1000 0000
127 :0111 1111
3.判断一个数是否为偶数
如果一个数是偶数,那么这个数的二进制数的最后一位为0,和1做与运算结果为0,反之,结果为1.

if(n & 1 ) {
 // n为奇数
 }

多数时候判断奇偶性的代码如下:


if(!(n % 2)) {
  //n为奇数
}

但是位运算更快
4.找出不重复的数 今天的重头戏
x ^ y ^ y = x;

经过一段时间的紧张筹备,电脑小组的“RP餐厅”终于开业了,这天,经理LXC接到了一个定餐大单,可把大家乐坏了!员工们齐心协力按要求准备好了套餐正准备派送时,突然碰到一个棘手的问题,筷子!CX小朋友找出了餐厅中所有的筷子,但遗憾的是这些筷子长短不一,而我们都知道筷子需要长度一样的才能组成一双,更麻烦的是CX找出来的这些筷子数量为奇数,但是巧合的是,这些筷子中只有一只筷子是落单的,其余都成双,善良的你,可以帮CX找出这只落单的筷子的长度吗?
输入格式

第一行读入一个数N,它代表CX找到的筷子的根数。

第二行是N个用空格隔开的数,代表筷子的长度。
输出格式

一行,落单的筷子的长度。
输入输出样例
输入 #1

9
2 2 1 3 3 3 2 3 1

输出 #1

2

说明/提示

对于60%的数据,N<=100001;

对于100%的数据,N<=10000001,筷子长度不大于 10^9。

内存限制4MB
分析:首先可以发现内存限制,所以最简单直接的桶排就不太友好,而这题如果用位运算的话,完全不用担心内存问题啦。话不多说,上代码。

#include<iostream>
int main() {
    std::ios::sync_with_stdio(false);
    int n, t, x;
    std::cin>>n;
    for(int i = 0; i < n; ++i){
      std::cin>>x;
      t ^= x;
    }
     std::cout<<t<<"\n";
}
  • 例题2只出现一次的数
    给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现了三次。找出那个只出现了一次的元素。

说明:

你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?

示例 1:

输入: [2,2,3,2]
输出: 3

示例 2:

输入: [0,1,0,1,0,1,99]
输出: 99

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/single-number-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

#include<stdio.h>
int x, sum, a[32];
int main() {
    while(~scanf("%d", &x)) {
      if(!x) continue;
      for(int i = 0; i < 32; ++i) {
        a[i] += ((x>>i) & 1);
      }
    }
    for(int i = 0; i < 32; ++i) {
      if(a[i] % 3 != 0) {
        sum +=(1 << i);
      }
    }
    printf("%d",sum);
}

这一天学校组织了一个游戏,找找谁才是倒霉蛋。
题目描述

分别让n个人每个人都拿一个号码a[i] (i < n && a[i] < 2^31),每两个人之间相互看号码,如果号码相同的话就可以一起出去,否则还必须接着看其他人的,这个游戏保证最后1个人或者2个留下来。
输入格式

第一行两个数 n,k (n≤3000000,1≤k≤2),n表示参加游戏的人数,接下来 n行每行一个正整数表示游戏上每一个人的密码,k表示最后留在游戏的人数。
输出格式

从小到大输出一行 k个数,表示最后留在游戏里的倒霉蛋,中间用空格分隔.
输入输出样例
输入 #1

3 1
2 2 2

输出 #1

2

#include<iostream>
using namespace std;
const int N = 3e6 + 6;
int a[N];
int re[2];
int main() {
    ios::sync_with_stdio(false);
    int n, k, x, t;
    cin>>n>>k;
    if(k==1) {
      for(int i = 1; i <= n; ++i) {
        cin>>x;
        t ^= x; 
      }
      cout<<t;
    }else {
      for(int i = 1; i <= n; ++i) {
        cin>>a[i];;
        t ^= a[i];
      }
      t &= -t;
      for(int i = 1; i <= n; ++i) {
        if((t & a[i]) != 0) {
          re[0] ^= a[i];
        }else {
          re[1] ^= a[i];
        }
      }
      if(re[0] > re[1]) swap(re[0], re[1]);
      cout<<re[0]<<' '<<re[1];
    }
    return 0;
}
发布了5 篇原创文章 · 获赞 2 · 访问量 438

猜你喜欢

转载自blog.csdn.net/qq_45886817/article/details/104147373