OJ刷题:《剑指offer》之单身狗1、2 !(巧用位操作符,超详细讲解!)

简介: OJ刷题:《剑指offer》之单身狗1、2 !(巧用位操作符,超详细讲解!)

1.单身狗1


1.1 题目描述


在一个整型数组中,只有一个数字出现一次,其他数组都是成对出现的,请找出那个只出现一次的数字。


例如:

数组中有:1 2 3 4 5 1 2 3 4,只有5出现一次,其他数字都出现2次,出5


1.2排序寻找


1. 对于一个无序的数组,当我们将他们进行排序后,一切问题都会简单很多的~


冒泡排序的伪代码~

void sort(int arr[], int len)
{
  int i = 0;
  int j = 0;
  for (i = 0; i < len - 1; i++)
  {
    int flag = 1;
    for (j = 0; j < len - 1; j++)
    {
      if (arr[j] > arr[j + 1])
      {
        int tmp = arr[j];
        arr[j] = arr[j + 1];
        arr[j + 1] = tmp;
        flag = 0;
      }
    }
    if (flag == 1)
      break;
  }//冒泡排序-》升序数组
}


2. 那我们要如何找到那个“单身狗”呢~


我们可以很容易的注意到相邻的2个元素是相同的,那我们是不是可以俩俩比较呢,若不同,则前面的那个元素一定就是“单身狗”啦~


下面是这部分的伪代码~

for (i = 0; i < len; i+=2)
{
  if (arr[i] != arr[i + 1])
  {
    printf("单身狗数字是:%d\n", arr[i]);
    break;
  }
}


3. 不过,我们还要考虑边界情况呢~


当我们将前面的元素都比较完后,还没有找到单身狗,而按照上面的算法逻辑的话,最后那个元素是无法俩俩比较的,那我们该怎么办呢~


我们不妨立个flag=1;若在上面的逻辑中找到单身狗,flag=0,若没有找到,flag还是=1,

那单身狗就是最后那个元素啦~

int flag = 1;
for (i = 0; i < len; i+=2)
{
  if (arr[i] != arr[i + 1])
  {
    printf("单身狗数字是:%d\n", arr[i]);
    flag = 0;
    break;
  }
}
if (flag == 1)
  printf("单身狗数字是:%d\n", arr[len-1]);

1.3巧用位操作符


1. 这个题目其实还有更为巧妙的方法呢~

这里先给俩个结论:1.相同的俩个元素^(抑或)结果为零~

                                2.零与其他元素抑或结果为那个元素本身~

那是为什么呢~(其实在我之前的博客也提到过,这里再说明一下)http://【有趣的移位操作符和位操作符(由浅入深轻松搞定!) - CSDN App】http://t.csdnimg.cn/q2ubr


2. 好了,知道了这些那这个题目就显得异常简单了啦~


我们将所有元素抑或起来是不是就找到了那个单身狗呢~

下面是这部分的伪代码~

int find_single_dog(int arr[], int sz)
{
    int ret = 0;
    int i = 0;
    for (i = 0; i < sz; i++)
    {
        ret ^= arr[i];
    }
    return ret;
}//sz是数组的长度


2.单身狗2


2.1 题目描述


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

编写一个函数找出这两个只出现一次的数字。


例如:

有数组的元素是:1,2,3,4,5,1,2,3,4,6

只有5和6只出现1次,要找出5和6.


2.2排序寻找


1.这个题目如果用排序来做的话,主要的算法部分其实和前面的是差不多的~

唯一不同的是我们要找的俩个“单身狗”后才能结束寻找~


我们可以用count来计数,当count==2时,就结束寻找~

代码如下~

for (i = 0; i < len-1; i+=2)
{
  if (arr[i] != arr[i + 1])
  {
    printf("单身狗是%d\n", arr[i]);
    count++;
    i--;
  }
  if (count == 2)
    break;
}


2. 当然我们还要考虑边界情况的~


我们可以很容易的知道上面的代码逻辑一定可以至少找到一个单身狗5

当循环结束后i是等于len-1的,所以优化后的代码如下~

  for (i = 0; i < len-1; i+=2)
  {
    if (arr[i] != arr[i + 1])
    {
      printf("单身狗是%d\n", arr[i]);
      count++;
      i--;
    }
    if (count == 2)
      break;
  }
  if(i==len-1)
    printf("单身狗是%d\n", arr[i]);//考虑边界情况
}


2.3巧用位操作符


1. 上面的代码还是不够牛逼,让我们看看牛逼的代码~

当单身狗只有一个时,我们可以用位操作的方法快速找到,这里有俩个不同的元素,这时我们就不可以简单的将他们全部抑或起来了,那怎么办呢~


2. 我们可不可以想办法将这俩个单身狗分开来后再进行抑或呢~(举个栗子,数据不一定正确分配)


3. 我们先将所有元素抑或起来(还是以上面的元素为例~)


然后我们将结果放到临时变量tmp中,那tmp到底有什么用呢~


我们仔细思考一下就会惊奇的发现(找到tmp二进制中第一个1(相异为1)可以区分俩个不同的单身狗!)即:找到有分歧的一位。在这一位上,两个数一定是一个1一个0

找tmp二进制中的第一个1的代码如下~

//找到tmp二进制中第一个1(相异为1)区分俩个不同的元素
int count = 0;//用count来记录tmp二进制中的第一个1
while ((tmp & (1<<count))==0)
{
  count++;
}


4. 最后,我们要将数组中的所有元素右移count位后再与一按位与(此时一定可以将不同的单身狗区分开来,至于其他相同的元素不管他们那一位上是1还是0都会被分配到相同的部分)

//数组中的元素右移count后&1
for (int i = 0; i < len; i++)
{
  if (((arr[i] >>= count) & 1) == 1)
    *tmp1^= arr[i];
  else
    *tmp2^= arr[i];
}

注:tmp1和tmp2一定要初始化为零呢~,还要注意运算符的优先级(一定要加括号按照我们的思路计算!)


附:完整的代码~

void Fun(int arr[], int*tmp1, int*tmp2, int len)
{
  int tmp = 0;
  //将所有元素抑或起来结果放到tmp中
  for (int i = 0; i < len; i++)
     tmp ^= arr[i];
  //找到tmp二进制中第一个1(相异为1)区分俩个不同的元素
  int count = 0;//用count来记录tmp二进制中的第一个1
  while ((tmp & (1<<count))==0)
  {
    count++;
  }
  //数组中的元素右移count后&1
  for (int i = 0; i < len; i++)
  {
    if (((arr[i] >>= count) & 1) == 1)
      *tmp1^= arr[i];
    else
      *tmp2^= arr[i];
  }
}
相关文章
|
6月前
OJ刷题:猜名次和找凶手
OJ刷题:猜名次和找凶手
32 0
|
6月前
|
C++
【洛谷 P1428】小鱼比可爱 题解(循环)
这是一个编程竞赛问题,题目要求编写一个程序来计算每只鱼在其视野内看到的更不可爱的鱼的数量。给定鱼的总数`n`和每只鱼的可爱程度数组`a[]`,输出每个位置的鱼能看到的更不可爱的鱼的数量。 **摘要:** ```markdown 解决一个编程挑战,计算鱼在“比可爱”比赛中左边有多少条更不可爱的鱼。输入包含鱼的总数`n`和每条鱼的可爱度,输出每条鱼眼中更不可爱的鱼数。提供的C++代码通过遍历数组,比较每只鱼的可爱度并累计小于它的数量,然后输出结果。 ``` 这个摘要在240个字符以内,简要概述了问题的背景、任务和解决方案的概要。
66 0
|
6月前
|
C语言
C语言——oj刷题——找单身狗2
C语言——oj刷题——找单身狗2
39 0
|
6月前
|
C语言
C语言——oj刷题——找单身狗1
C语言——oj刷题——找单身狗1
36 0
|
7月前
|
数据安全/隐私保护 C++ 索引
【一刷《剑指Offer》】面试题 4:替换空格
【一刷《剑指Offer》】面试题 4:替换空格
|
7月前
【一刷《剑指Offer》】面试题 6:重建二叉树
【一刷《剑指Offer》】面试题 6:重建二叉树
|
C语言
【C语言】【典例详解】【刷题】猜名次&&猜凶手【循环练习】
【C语言】【典例详解】【刷题】猜名次&&猜凶手【循环练习】
191 0
【每日易题】七夕限定——单身狗问题以及进阶问题位运算法的深入探讨
【每日易题】七夕限定——单身狗问题以及进阶问题位运算法的深入探讨
109 0
卡特兰数—以leetcode22括号生成为例(笔记)
卡特兰数—以leetcode22括号生成为例(笔记)
|
存储 算法 Java
代码随想录刷题|LeetCode 332.重新安排行程 51. N皇后 37. 解数独
代码随想录刷题|LeetCode 332.重新安排行程 51. N皇后 37. 解数独
代码随想录刷题|LeetCode 332.重新安排行程 51. N皇后 37. 解数独

热门文章

最新文章