leetcode136:single number I&II 及拓展

Single Number I

给定一个数组,除了一个元素出现一次之外,其余的元素都出现次。找出这个元素

分析:

只要将所有的元素都异或一次,最后的结果就是这个出现一次数。

代码:
int singleNumber(int A[], int n) {
    int num;
    int i;
    num=A[0];
    for(i=1;i<n;i++)
    {
        num=num^A[i];
    }
    return num;
}

Single Number II

给定一个数组,除了一个元素出现一次之外,其余的元素都出现次。找出这个元素

分析:

考虑全部用二进制表示,将sizeof(int)大小的数组,每一位记录所有数字对应为1的个数。然后我们把 第 ith 个位置上所有数字的和对3取余,那么只会有两个结果 0 或 1 (根据题意,3个0或3个1相加余数都为0). 因此取余的结果就是那个出现一次的数。详细可以参考一下这篇博文

代码:
 int singleNumber(int A[], int n) {
        int count[32]={0};
        int result=0;
        for(int i=0;i<32;i++)
          {
              for(int j=0;j<n;j++)
             {
                 if((A[j]>>i)&1)
                   count[i]++;
             }
             result|=((count[i]%3)<<i);  
          }
        return result;
    }

拓展一

一个数组,其中除两个数外,其余的都是成对出现的,找出这两个数

分析:

把数组中的所有元素异或,得到的结果为那两个不成对出现的数的异或值。然后在异或结果中找到第一个为1的位的位置,记为第N位。现在以第N位是不是1为标准把原数组中的数字分成两个子数组,第一个子数组中每个数字的第N位都为1,而第二个子数组的每个数字的第N位都为0。
现在我们已经把原数组分成了两个子数组,每个子数组都包含一个只出现一次的数字,而其他数字都出现了两次。
详细分析请见:链接 代码复制过来贴在下面了。

代码:
///////////////////////////////////////////////////////////////////////
// Find two numbers which only appear once in an array
// Input: data - an array contains two number appearing exactly once,
//               while others appearing exactly twice
//        length - the length of data
// Output: num1 - the first number appearing once in data
//         num2 - the second number appearing once in data
///////////////////////////////////////////////////////////////////////
void FindNumsAppearOnce(int data[], int length, int &num1, int &num2)
{
      if (length < 2)
            return;

      // get num1 ^ num2
      int resultExclusiveOR = 0;
      for (int i = 0; i < length; ++ i)
            resultExclusiveOR ^= data[i];

      // get index of the first bit, which is 1 in resultExclusiveOR
      unsigned int indexOf1 = FindFirstBitIs1(resultExclusiveOR);

      num1 = num2 = 0;
      for (int j = 0; j < length; ++ j)
      {
            // divide the numbers in data into two groups,
            // the indexOf1 bit of numbers in the first group is 1,
            // while in the second group is 0
            if(IsBit1(data[j], indexOf1))
                  num1 ^= data[j];
            else
                  num2 ^= data[j];
      }
}

///////////////////////////////////////////////////////////////////////
// Find the index of first bit which is 1 in num (assuming not 0)
///////////////////////////////////////////////////////////////////////
unsigned int FindFirstBitIs1(int num)
{
      int indexBit = 0;
      while (((num & 1) == 0) && (indexBit < 32))
      {
            num = num >> 1;
            ++ indexBit;
      }

      return indexBit;
}

///////////////////////////////////////////////////////////////////////
// Is the indexBit bit of num 1?
///////////////////////////////////////////////////////////////////////
bool IsBit1(int num, unsigned int indexBit)
{
      num = num >> indexBit;

      return (num & 1);
}

拓展 二

1-100当中缺了两个数,求出这两个数

分析:

简单的数学方法是:计算 a+b ab 的值,解方程求解
这里考虑转化为拓展一的方法。数组array[100],其下标正好为0-99,能不能利用上数组下标求解呢?答案是肯定的。这里将数组下标加一,变为1-100。将题目转化为array[0]…array[99]以及1-100 这总共200个数中,两个只出现一次的数。实现代码如下:

代码:
void find_lost_two(int array[],int length,int* num1,int* num2)  
{  
    *num1 = 0;  
    *num2 = 0;  
    int temp = 0,i;  
    /* 计算200个数的异或和 */  
    for(i=0;i<100;i++)  
    {  
        temp ^=(i+1);  
        temp ^=array[i];  
    }  

    int first_not_zero=1;  
    /*找出异或和的最低1的位数*/  
    while(temp%2 == 0)  
    {  
        first_not_zero++;  
        temp = temp>>1;  
    }  
    /*按1进行划分*/  
    for(i=0;i<100;i++)  
    {  
        if(((1<<(first_not_zero-1))&(i+1)) == 0)  

            *num1 ^=(i+1);  
        else  
            *num2 ^=(i+1);  
        if(((1<<(first_not_zero-1))&array[i]) == 0)  
            *num1 ^=array[i];  
        else  
            *num2 ^=array[i];  
    }  
}  

参考资料:

1、http://zhedahht.blog.163.com/blog/static/2541117420071128950682/
2、http://blog.csdn.net/baidu20008/article/details/22095149

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值