剑指offer题库总结(一)之数组(C语言版本)

本文总结了剑指offer题库中关于数组的题目,包括找到数组中只出现一次的两个数字、唯一只出现一次的数字以及出现三次的重复数字。文章详细解析了使用异或操作、哈希表等方法来解决这些问题,时间复杂度和空间复杂度各有优化,适合面试复习。
摘要由CSDN通过智能技术生成

剑指offer题库总结(一)之数组(C语言版本)

题56:数组中只出现一次的两个数字

  • 题目具体要求:一个整型数组里除了两个数字只出现一次,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。
  • 数据范围:数组长度 2≤n≤1000,数组中每个数的大小 0 < val ≤1000
  • 要求:空间复杂度 O(1),时间复杂度 O(n)
  • 提示:输出时按非降序排列。
    示例1
    输入:[1,4,1,6]
    返回值:[4,6]
    说明:返回的结果中较小的数排在前面
  • 解题思路
    1.总体思路:有一道和它类似的题,它所指的数组中只有一个出现一次的数,而解法就是从头开始不断地异或下去,由于相同的两个数异或值为0,因此最终的异或结果就是答案
    2.而本题有两个只出现一次的数a和b,我们按异或方法最终只能得到a异或b的值,就需要思考一下这两个数异或的结果有何特点
    3.我们可以发现,首先这两个数一定不同,故异或结果一定不为0,那么a异或b的结果中一定有一位为1,假设是第x位,那么就说明了a和b的二进制的第x位是不同,根据这一特点,我们可以将数组分为两个集合,即第x位为1的数和第x位为0的数,两部分的异或和即为a和b的值
    4.要快速求得最后一位1,可以用lowbit运算(即x&(-x)),它可以快速得到x的最后一位1。
/**
 * @param array int整型一维数组 
 * @param arrayLen int array数组长度
 * @return int整型一维数组
 * @return int* ResultArr 返回结果数组
 */
#include <cstdio>
int* FindNumsAppearOnce(int* data, int length, int *ResultArr) {
   
    // write code here
    int Temp = 0;
    int idx;
    int mask = 1;
    int resultA = 0;
    int resultB = 0;
    // 先将全部数进行异或运算,即得出这两个不同数的异或结果
    for (idx = 0; idx < length; idx++)
    {
   
        Temp ^= data[idx];
    }
    //从最低位开始找这个异或结果的bit位首次出现1的位置,即mask的值。
    //以下while循环可以用位运算代替:mask = mask << (((0 - Temp) & Temp) - 1);  
    //一个数和其相反数做位与算,得到的是该数自身首次出现1的位置(最低比特计为索引1);
    //如:10 &(-10)= 2;对应10的二进制为1010;
    while ((Temp & mask) == 0)
    {
   
        mask = mask << 1;
    }
    //将原始数组拆分成2组,分别进行异或累算。
    for (idx = 0; idx < length; idx++)
    {
   
        if ((data[idx] & mask) == 0)
        {
   
            resultA ^= data[idx];
        }
        else
        {
   
            resultB ^= data[idx];
        }
    }
    if (resultA > resultB)
    {
   
        Temp = resultA;
        resultA = resultB;
        resultB = Temp;
    }
    *ResultArr = resultA;
    *(ResultArr + 1) = resultB;
    return ResultArr;
}

// ====================测试代码====================
void Test(const char* testName, int data[], int length, int expected1, int expected2)
{
   
    if (testName != nullptr)
        printf("%s begins: ", testName);

    int result[2];
    FindNumsAppearOnce(data, length, &result[0]);

    if ((expected1 == result[0] && expected2 == result[1]) ||
        (expected2 == result[0] && expected1 == result[1]))
        printf("Passed.\n\n");
    else
        printf("Failed.\n\n");
}

void Test1()
{
   
    int data[] = {
    2, 4, 3, 6, 3, 2, 5, 5 };
    Test("Test1", data, sizeof(data) / sizeof(int), 4
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值