zoukankan      html  css  js  c++  java
  • 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的韦恩图
    xones原twos原 00 01 10 11
    0 0 0 1 x
    1 1 0 0 x
    twos的韦恩图
    xonestwos原 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
  • 相关阅读:
    指令到底是什么?机器码又是什么?
    汇编基础最后一篇--机器语言指令
    剑指OFFER----面试题34. 二叉树中和为某一值的路径
    剑指OFFER----面试题33. 二叉搜索树的后序遍历序列
    剑指OFFER----面试题32
    剑指OFFER----面试题31. 栈的压入、弹出序列
    剑指OFFER----面试题30. 包含min函数的栈
    剑指OFFER----面试题29. 顺时针打印矩阵
    剑指OFFER----面试题28. 对称的二叉树
    剑指OFFER----面试题27. 二叉树的镜像
  • 原文地址:https://www.cnblogs.com/zaq19970105/p/10733364.html
Copyright © 2011-2022 走看看