位运算的奇淫技巧

1.组数据中只有一个数字出现了一次。
其他所有数字都是成对出现的。请找出这个数字。

a ^ b ^ b = a;

因为只有一个数恰好出现一个,剩下的都出现过两次,所以只要将所有的数异或起来,就可以得到唯一的那个数。

#include<stdio.h>
int find(char *str,int sz)
{
   int i = 0;
   int tmp = 0;
    for(i = 0; i < sz;i ++)
    {
       tmp^ = str[i];
    }  
    return tmp;
}
int main(void)
{
char arr[]={1,2,3,4,1,2,3};
int sz = sizeof(arr)/sizeof(arr[0]);
int ret = find(arr,sz);
printf("%d\n",ret);
return 0;
}

2,一个数组中只有两个数字是出现一次,其他所有数字都出现了两次。
找出这两个数字.

有了第一题的基本的思路,我们可以将数组分成两个部分,每个部分里只有一个元素出现一次,其余元素都出现两次。那么使用这种方法就可以找出这两个元素了。 不妨假设出现一个的两个元素是x,y,那么最终所有的元素异或的结果就是res = x^y。并且res!=0,那么我们可以找出res二进制表示中的某一位是1。对于原来的数组,我们可以根据这个位置是不是1就可以将数组分成两个部分。x,y在不同的两个子数组中。而且对于其他成对出现的元素,要么在x所在的那个数组,要么在y所在的那个数组。

#include<stdio.h>
int find(char * str,int sz,int *x,int *y)
{
   *x = 0;
   *y = 0;
   int pos = 0;
   int i = 0;
   int tmp = 0;
   for(i = 0; i < sz;i ++)
   {
            tmp ^=str[i];
         }
  for(i = 0; i < 32; i++)
  {
      if((tmp>>i)&1==1)
      {
      pos = i;
      break;
      }
  for(i = 0 ; i< sz; i++)
  {
    if((str[i]>>pos)&1==1)
    {
         *x^ = str[i];
    }

}
 *y = *x^tmp;
 }
int main(void)
{
int x = 0;
int y = 0;
char arr[]={1,2,3,4,1,2,3,5};
int sz = sizeof(arr)/sizeof(arr[0]);
find(arr,sz,&x,&y);
printf("%d\n%d\n",x,y);
return 0;

3.数组中,只有一个数出现一次,剩下都出现三次,找出出现一次的

因为数是出现三次的,也就是说,对于每一个二进制位,如果只出现一次的数在该二进制位为1,那么这个二进制位在全部数字中出现次数无法被3整除。 膜3运算只有三种状态:00,01,10,因此我们可以使用两个位来表示当前位%3,对于每一位,我们让Two,One表示当前位的状态,B表示输入数字的对应位,Two+和One+表示输出状态。

0 0 0 0 0
 0 0 1 0 1
 0 1 0 0 1
 0 1 1 1 0
 1 0 0 1 0
 1 0 1 0 0
 One+ = (One ^ B) & (~Two)
 Two+ = (~One+) & (Two ^ B)
这个问题大家可以思考一下,下次我再更新
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值