• 136.只出现一次的数字


    给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。

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

    示例 1:

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

    示例 2:

    输入: [4,1,2,1,2]
    输出: 4


    1.暴力法:排序后,以sizeof(int)*2为一个单元来遍历,当发现一个单元内的两个数字不同,输出该单元第一个数字。

    int cmpfunc (const void * a, const void * b)
    {
       return ( *(int*)a - *(int*)b );
    }
    
    int singleNumber(int* nums, int numsSize)
    {
    if(numsSize==1) return nums[0]; qsort(nums, numsSize, sizeof(int), cmpfunc); for(int j = 0; j <numsSize-1 ; j+=2 ) { if(nums[j]!=nums[j+1]) { return nums[j]; } } return nums[numsSize-1]; }

    2.异或法

    ①运用异或运算的交换律

    即:a^b^c^d=a^c^d^b ,任意交换位置,结果都相等

    ②运用异或运算的本质

    即:a^a=0,0^a=a

    int singleNumber(int* nums, int numsSize)
    {
      int sum = nums[0];   for(int i = 1;i < numsSize;i++)
      {     sum
    ^= nums[i];   }   return sum; }

    3.递归异或法:

    核心要义,从数组最后一个元素开始异或到第一个元素,

    擦边球:最先return的是numsSize=1,在这一层,由于该三目运算符的特性,并不会计算后面那个非法调用的函数,但语法规则是合法的。

    实际上这种办法比方法②还要糟糕,甚至有时候比方法①还要糟糕,递归调用需要消耗大量函数栈,也就是栈空间,不过看上去是相当华丽。

    int singleNumber(int* nums, int numsSize)
    {
      return numsSize==1?nums[0]:(singleNumber(nums+1,numsSize-1)^nums[0]); }

    4.hash:

    这里实现hash的关键是a[nums[i]-min]这一步,可以保证a数组的下标都为正。出现两次的位置的元素都会是累加两次,没出现的位置为0,仅出现一次的地方只会累加一次。

    int singleNumber(int* nums, int numsSize){
        if(numsSize == 1)
        return nums[0];
    
        int i = 0;
        int max = nums[0];
        int min = nums[0];
    
        for(i = 0; i<numsSize; i++)
        {
            max = max > nums[i]? max:nums[i];
            min = min < nums[i]? min:nums[i];
        }
        max = max-min+1;
        int a[max];//声明一个考虑了最坏情况的最小数组,来承接数字
        memset(a,0,sizeof(int)*(max));
        for(i = 0; i<numsSize; i++)
        {
            a[nums[i]-min] += 1;
        }
        for(i = 0; i < numsSize; i++)
        {
            if(a[nums[i]-min] == 1)
            {
                return nums[i];
            }
        }
        return 0;
    }

    总结:出现概率型+数组的问题,首先考虑hash,其次考虑运算特性。

  • 相关阅读:
    代码块;继承;this与super关系;重载与重写对比;类的继承特点;final关键字 (Java Day08)
    变量访问;this关键字;静态;工具类;帮助文档;Math使用;Arrays使用(Java Day07)
    面向对象;类和对象;访问对象;创建对象在内存中的理解;匿名对象;封装和this (Java Day06)
    如何保证 RocketMQ 不丢失消息
    Java-String类型的参数传递问题
    图解前中后序遍历
    一文彻底理解ReentrantLock可重入锁的使用
    聊聊MySQL、HBase、ES的特点和区别
    MySQL vs Java 数据类型
    Multi-Tenancy多租户模式
  • 原文地址:https://www.cnblogs.com/still-smile/p/13296725.html
Copyright © 2020-2023  润新知