zoukankan      html  css  js  c++  java
  • 【LeetCode】只出现一次的数字系列问题(I、II、III)

    (一)只出现一次的数字(其他两次)

    题目(Easy):136. 只出现一次的数字

    题目描述:

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

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

    示例 1:

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

    示例 2:

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

    解题思路:

      利用异或的性质
    x ^ x = 0
    0 ^ x = x,相同为0,相异为1,通过异或相同的数抵消掉了,剩下一个多余的数。

    代码实现:

    class Solution {
        public int singleNumber(int[] nums) {
            int res=0;
            for(int num:nums){
                res ^= num;
            }
            return res;
        }
    }
    

    (二)只出现一次的数字II (其他三次)

    题目(Medium):137. 只出现一次的数字 II

    题目描述:

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

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

    示例 1:

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

    示例 2:

    	输入: [0,1,0,1,0,1,99]
    	输出: 99
    

    解题思路:

      方法一:

      统计所有数字中每个位中1出现的总数,那么对于某个位,1出现的次数一定是3的倍数+1或0,那么对这个数%3得到的结果就是目的数字在该位上的值。

      方法二:

      为了区分出现一次的数字和出现三次的数字,使用两个位掩码:seen_onceseen_twice

      思路是:

    • 仅当 seen_twice 未变时,改变 seen_once
    • 仅当 seen_once 未变时,改变seen_twice

    代码实现:

    //方法一
    class Solution {
        public int singleNumber(int[] nums) {
            int res=0;
            //依次考虑每一位
            for(int i=0;i<32;i++){
                int count=0;
                //统计该位1的总个数
                for(int num:nums){
                    if((num>>i & 1)==1)
                        count++;
                }
                if(count%3!=0)
                    res = res | (1<<i);
            }
            return res;
        }
    }
    //方法二:
    class Solution {
        public int singleNumber(int[] nums) {
            int seenOnce = 0, seenTwice = 0;
    
        for (int num : nums) {
          // first appearence: 
          // add num to seen_once 
          // don't add to seen_twice because of presence in seen_once
    
          // second appearance: 
          // remove num from seen_once 
          // add num to seen_twice
    
          // third appearance: 
          // don't add to seen_once because of presence in seen_twice
          // remove num from seen_twice
          seenOnce = ~seenTwice & (seenOnce ^ num);
          seenTwice = ~seenOnce & (seenTwice ^ num);
        }
    
        return seenOnce;
    
        }
    }
    

    (三)只出现一次的数字III(两个一次)

    题目(Medium):260. 只出现一次的数字 III

    题目描述:

    给定一个整数数组 nums,其中恰好有两个元素只出现一次,其余所有元素均出现两次。 找出只出现一次的那两个元素。

    示例 :

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

    解题思路:

      具体参见:【剑指Offer】40、数组中只出现一次的数字

      首先仍然从前向后依次异或数组中的数字,那么得到的结果是两个只出现一次的数字的异或结果,其他成对出现的数字被抵消了。由于这两个数字不同,所以异或结果肯定不为0,也就是这个异或结果一定至少有一位是1,我们在结果中找到第一个为1的位的位置,记为第n位。接下来,以第n位是不是1为标准,将数组分为两个子数组,第一个数组中第n位都是1,第二个数组中第n位都是0。这样,便实现了我们的目标。最后,两个子数组分别异或则可以找到只出现一次的数字。

    代码实现:

    class Solution {
        public int[] singleNumber(int[] nums) {
            int[] result=new int[2];
            //1、先把所有的数字异或一次,得到的是要找的两个数的异或
            int res=0;
            for(int num:nums)
                res ^= num;
            
            //2、找到异或结果中第一个不为0的位
            int index=0;
            while(index<32){
                if(((res>>index)&1)==1)
                    break;
                index++;
            }
    
            //3、按照第index位是0还是1分别异或
            for(int num:nums){
                if(((num>>index)&1)==1)
                    result[0] ^= num;
                else
                    result[1] ^= num;
            }
            return result;
        }
    }
    

    总结:

      只出现一次的数字这三道题,主要涉及到的是位运算的相应问题,特别是异或运算和移位运算的巧妙应用,位运算相对理解起来有一定的难度,需要深入理解。

  • 相关阅读:
    Handlerbars基础笔记
    each()和eq()
    可编辑表格(Editable Table)
    垂直居中vertical-align
    CSS属性的私有前缀
    CSS进阶知识
    CSS预处理器们
    CSS3之伪元素选择器和伪类选择器
    CSS基础复习
    Plan
  • 原文地址:https://www.cnblogs.com/gzshan/p/12535178.html
Copyright © 2011-2022 走看看