Leetcode SingleNumber I & II & III 136/137/260

SingleNumber I:

题目链接:https://leetcode-cn.com/problems/single-number/

题意:

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

  说明:

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

  示例 1:

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

  示例 2:

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

分析:

  利用异或(xor)运算,两个相同的数异或为0

代码如下:

 1 class Solution {
 2 public:
 3     int singleNumber(int A[], int n) {
 4         int ans = 0;
 5         for(int i = 0; i < n; ++i) {
 6             ans ^= A[i];
 7         }
 8         return ans;
 9     }
10 };
View Code

 

SingleNumber II:

题目链接:https://leetcode-cn.com/problems/single-number-ii/

借鉴:https://www.cnblogs.com/grandyang/p/4263927.html

题意:

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

说明:

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

示例 1:

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

示例 2:

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

分析1:

  与第一题的不同是这里相同的数出现了3次,如果能定义一种3进制异或运算,就可以以第一题的方式解出这道题了。

代码如下:

 1 class Solution {
 2 public:
 3     int singleNumber(vector<int>& nums) {
 4         int res = 0;
 5         for (int i = 0; i < 32; ++i) {
 6             int sum = 0;
 7             for (int j = 0; j < nums.size(); ++j) {
 8                 // 取nums[j]的第i位值,然后加起来
 9                 sum += (nums[j] >> i) & 1;
10             }
11             // sum目前的有进位相加的结果,模3以后就是无进位相加的结果
12             res |= (sum % 3) << i;
13         }
14         return res;
15     }
16 };
View Code

 

分析2:

  还有一种解法,思路很相似,用3个整数来表示INT的各位的出现次数情况,one表示出现了1次,two表示出现了2次。当出现3次的时候该位清零。最后答案就是one的值。

  1. ones   代表第ith 位只出现一次的掩码变量
  2. twos  代表第ith 位只出现两次次的掩码变量
  3. threes  代表第ith 位只出现三次的掩码变量

代码如下:

 1 class Solution {
 2 public:
 3     int singleNumber(vector<int>& nums) {
 4         int one = 0, two = 0, three = 0;
 5         for (int i = 0; i < nums.size(); ++i) {
 6             // one & nums[i]的结果某一位上为1意味着这一位在上一轮出现过一次,在这一轮又出现过一次,那么也就意味着出现了两次
 7             // two此时包含所有出现过2次和3次的
 8             two |= one & nums[i];
 9             // one的某一位为1,表示之前出现过1次。如果nums[i]对应位为0,one的某一位没有变化;如果nums[i]对应位为1,one的某一位变为0,表示这一位出现2次了。
10             // one的某一位为0,表示之前出现过0次或2次。如果nums[i]对应位为0,one的某一位没有变化;如果nums[i]对应位为1,one的某一位变为1,表示这一位出现过1次或3次。
11             // one此时包含所有出现过1次和3次的
12             one ^= nums[i];
13             three = one & two;
14             // 消掉3次的
15             one &= ~three;
16             two &= ~three;
17         }
18         return one;
19     }
20 };
View Code

 

分析3:

  和分析2一样,不过这次只需要2个变量。

  1. ones   代表第ith 位只出现一次的掩码变量
  2. twos  代表第ith 位只出现两次次的掩码变量

ones[i]原:ones第i位二进制位原来的值

twos[i]原:twos第i位二进制位原来的值

x[i]:所要异或的数的第i位二进制位的值

ones[i]:ones第i位二进制位异或后的值

ones[i]:ones第i位二进制位异或后的值

ones[i]原 twos[i]原 x[i] ones[i] twos[i]
0 0 0 0 0
0 1 0 0 1
1 0 0 1 0
1 1 0 x x
0 0 1 1 0
0 1 1 0 0
1 0 1 0 1
1 1 1 x x

 

ones的韦恩图
x\ones原twos原 00 01 10 11
0 0 0 1 x
1 1 0 0 x

 

twos的韦恩图
x\onestwos原 00 01 10 11
0 0 1 0 x
1 1 0 0 x

得到公式为:

ones = (ones ^ x) & ~twos;
twos = (twos ^ x) & ~ones;

代码如下:

 1 class Solution {
 2 public:
 3     int singleNumber(vector<int>& nums) {
 4         int twos = 0, ones = 0;
 5         for (int i = 0; i < nums.size(); ++i) {
 6             // ones ^ nums[i]后ones的某一位1可能表示原来出现过0次,也可能表示原来出现过2次
 7             // & ~twos表示把原来出现过2次的部分删掉
 8             ones = (ones ^ nums[i]) & ~twos;
 9             // twos ^ nums[i]后twos的某一位1可能表示目前出现过2次,也可能表示目前出现过1次
10             // & ~ones表示把目前出现过1次的部分删掉
11             twos = (twos ^ nums[i]) & ~ones;
12         }
13         return ones | twos;
14     }
15 };
View Code

 

SingleNumber III:

题目链接:https://leetcode-cn.com/problems/single-number-iii/

题意:

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

示例 :

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

注意:

    1. 结果输出的顺序并不重要,对于上面的例子, [5, 3] 也是正确答案。
    2. 你的算法应该具有线性时间复杂度。你能否仅使用常数空间复杂度来实现?

分析:

  将所有数异或一遍,那个异或完后一定有某一位是1,这意味着两个数在这一位上不同,因此只要把这一位上为0的数和为1的数分别全部异或一遍就能得到只出现一次的2个元素了。

代码如下:

 1 class Solution {
 2 public:
 3     vector<int> singleNumber(vector<int>& nums) {
 4         vector<int> ans;
 5         int a = 0, b = 0, lowbit = 0;
 6         
 7         for(int i = 0; i < (int)nums.size(); ++i) {
 8             lowbit ^= nums[i];
 9         }
10         
11         lowbit = lowbit & (-lowbit);
12         for(int i = 0; i < (int)nums.size(); ++i) {
13             if(nums[i] & lowbit) a ^= nums[i];
14             else b ^= nums[i];
15         }
16         
17         ans.push_back(a);
18         ans.push_back(b);
19         return ans;
20     }
21 };
View Code

 

posted @ 2019-04-18 23:43  梦樱羽  阅读(269)  评论(0编辑  收藏  举报
Live2D