Leetcode Note:1.Single Number问题

本文详细解析了LeetCode上的SingleNumber系列算法题,包括SingleNumber、SingleNumberII及SingleNumberIII,介绍了如何利用位运算解决这类问题的方法,适用于需要线性时间复杂度和常数空间复杂度的场景。

最近在leetcode刷算法题,很多题的解法有相通之处,特别是同一个系列的题目,把思路写下来可以帮助理解记忆,也方便以后复习。本文记录的是Single Number系列问题的解法,主要的思路是位运算。


136. Single Number

Given an array of integers, every element appears twice except for one. Find that single one.

Note:
Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory?

题意:
给定一个整数数组,除了一个元素外,其他每个元素都会出现两次。 找出那个落单的数。要求线性的时间复杂度,并且不使用额外空间。

分析:
如果没有要求不能使用额外空间,我们可以通过Hash来记录每个数出现的次数,最后输出只出现一次的数。

// TC: O(n), SC: O(n)
public int singleNumber(int[] nums) {
    Map<Integer, Integer> map = new HashMap<>();
    for (int x : nums) {
        map.put(x, map.getOrDefault(x, 0) + 1);
    }   
    for (int k : map.keySet()) {
        if (map.get(k) == 1) return k;
    }
    return 0;
}

但是本题要求不使用额外空间,我们可以通过位运算来解决。两个相同的数按位异或的结果为0,因此一次遍历,将所有的数按位异或,出现两次的数被消去,最后的值为落单的数。

// TC: O(n), SC: O(1)
public int singleNumber(int[] nums) {
    int answer = 0;
    for (int i = 0; i < nums.length; i++) {
        answer ^= nums[i];
    }
    return answer;
}

137. Single Number II

Given an array of integers, every element appears three times except for one, which appears exactly once. Find that single one.

Note:
Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory?

题意:
给定一个整数数组,除了一个元素外,其他每个元素都会出现三次。 找出那个落单的数。要求线性的时间复杂度,并且不使用额外空间。

分析:
此题是上题的变种,元素出现三次,不能再通过异或运算来消去相同的元素。此类题目在于统计每个比特位1出现的次数。

方法一: 对于int类型,依次统计32 bit每一位上1出现的次数,然后模3,余下1次就是single number出现的,这种方法是通用的,如出现3次改为出现5次,只需将模3改为模5. 上题采用这种解法也是没问题的。

// TC: O(n), SC: O(1)
public int singleNumber(int[] nums) {
    int answer = 0;
    for (int i = 0; i < 32; i++) {
        int count = 0;
        for (int num : nums) {
            if ((num >> i & 1) == 1) {
                count++;
            }
        }
        count %= 3;
        answer |= count << i;
    }
    return answer;
}

方法二: 用one记录出现一次的bit,two记录出现两次的bit,three记录出现三次的bit,每当有出现三次的bit时,将one,two中出现三次的bit置为0.

// TC: O(n), SC: O(1)
public int singleNumber(int[] nums) {
    int one = 0, two = 0, three;
    for (int num :nums) {
        two |= one & num;
        one ^= num;
        three = one & two;
        one = one & ~three;
        two = two & ~three;
    }
    return one;
}

260. Single Number III

Given an array of numbers nums, in which exactly two elements appear only once and all the other elements appear exactly twice. Find the two elements that appear only once.

For example:

Given nums = [1, 2, 1, 3, 2, 5], return [3, 5].

Note:

  1. The order of the result is not important. So in the above example, [5, 3] is also correct.
  2. Your algorithm should run in linear runtime complexity. Could you implement it using only constant space complexity?

题意:
给定一个整数数组,除了两个元素外,其他每个元素都会出现两次。 找出那个两个落单的数(两个数的顺序任意)。要求线性的时间复杂度,并且使用常数空间。

分析:
与第136题思路类似,通过按位异或消去相同的数,因为有两个落单的数字,所以应采用某种方式将原数组分成两部分处理。

  1. 第一次遍历将所有元素按位异或,得到x ^ y的值tx, y即要找的两个数);
  2. t的二进制中,出现1的位置都是x, y的不同之处,任意取一个出现1的位置(可以通过t & -t取最低位的1),与原数组的元素按位与,根据该位置是否出现1将原数组分成分别包含x, y的两部分(其他的元素中相同的一定会被分到同一部分);
  3. 分别将这两部分按位异或,得到x, y
public int[] singleNumber(int[] nums) {
    int t = 0;
    for (int num : nums) {
        t ^= num;
    }
    t &= -t;
    int[] answer = new int[2];
    for (int num : nums) {
        if ((t & num) != 0) {
            answer[0] ^= num;
        } else {
            answer[1] ^= num;
        }
    }
    return answer;
}

总结
此类型的题目,要求O(n)的时间复杂度和O(1)的空间复杂度或者不能使用额外空间。我们可以借助位运算的性质(如相同的元素进行异或运算结果为0),通过统计各个bit位1出现的次数来统计元素出现的次数,以及通过异或运算的结果来区分不同的元素。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值