LeetCode Java刷题笔记—137. 只出现一次的数字 II

137. 只出现一次的数字 II

给你一个整数数组 nums ,除某个元素仅出现 一次 外,其余每个元素都恰出现 三次 。请你找出并返回那个只出现了一次的元素。

中等难度。我们可以对每个二进制位单独计数,然后统计每个二进制位的1的计数值结果 %3的结果,如果结果是0,则表示只出现一次的元素的当前位为0;如果结果是1,则表示只出现一次的元素的当前位为1。

/**
 * 每个二进制位单独计数,然后统计每个二进制位的1的数量 mod 3的结果
 */
public int singleNumber( int[] nums ){
   //result表述最终返回的出现一次的数
   int result = 0;
   //对每个数的每一位进行单独统计
   for( int i = 0; i < 32; i++ ){
      //每个数的对应位的和
      int sum = 0;
      //对每个数进行对应位的值进行求和
      for( int num : nums ){
         //当前数右移i位,并且和1进行&运算,获取当前数的第i位的二进制的值,并且相加
         sum += ( ( num >> i ) & 1 );
      }
      //用和对3取模,获取对应位的运算结果,如果是0表示出现一次的数对应位是0,如果是1表示对应位是1
      //然后将运算结果左移i位,再与最终值进行与运算,这样就能让最终值对应位的值变成当前计算的结果值
      result |= ( ( sum % 3 ) << i );
   }
   //返回最终结果
   return result;
}

上面这种解法的好处是,此后对于出现了k个一样的数的题目,那么我们使用%k即可求解。

另一种更难理解的方法,使用纯粹的位运算,我们使用两个数,这两个数的对应位来记录最终返回的数的对应位的值的情况。

public int singleNumber( int[] nums ){

   int one = 0, two = 0;
   for( int num : nums ){
      one = one ^ num & ~two;
      two = two ^ num & ~one;
   }
   return one;
}

刚开始时,在第i位,a和b的对应位二进制值都是0。

在第i位如果第1次遇到1,则a对应位二进制值为1,a对应位二进制为0。

在第i位如果第2次遇到1,则a对应位二进制值为0,a对应位二进制为1。

在第i位如果第3次遇到1,则a对应位二进制值为0,a对应位二进制为0,回到原点。

后续的计算以此类推,我们发现,该位最终运算结束后的值就是只出现一次的元素对应位的值。

你可能感兴趣的:(java,137.,只出现一次的数字,leetcode)