二进制中 1 的个数 + 只出现一次的数字

122 阅读1分钟

题目描述

这是 LeetCode 上的 剑指 Offer II 003. 前 n 个数字二进制中 1 的个数 ,难度为 简单

Tag : 「位运算」、「动态规划」

给定一个非负整数 n ****,请计算 0 到 n 之间的每个数字的二进制表示中 1 的个数,并输出一个数组。

示例 :

输入: n = 2
输出: [0,1,1]
解释: 0 --> 0
1 --> 1
2 --> 10

动态规划

Brian Kernighan算法可以用于清除二进制数中最右侧的1。Brian Kernighan算法的做法是先将当前数减一,然后在与当前数进行按位与运算。

x=x&(x-1)

定义动态规划的转移函数

dp[i] = dp[i & (i - 1)] + 1

代码:

public int[] countBits(int n) {
    int[] dp = new int[n + 1];
    for (int i = 1; i <= n; i++) {
        dp[i] = dp[i & (i - 1)] + 1;
    }
    return dp;
}

题目描述

这是 LeetCode 上的 剑指 Offer II 004. 只出现一次的数字 ,难度为 中等

Tag : 「位运算」、「数组」

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

示例 :

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

提示:

  • 1 <= nums.length <= 3 * 104
  • -231 <= nums[i] <= 231 - 1
  • nums 中,除某个元素仅出现 一次 外,其余每个元素都恰出现 三次

位运算

朴素解法:哈希表,遍历整个数组,使用哈希表记录每个元素的出现次数。时间复杂度O(n), 空间复杂度O(n)。

进阶解法: 位运算,统计所有数值在每位上面出现了多少次1, 然后对3取余,如果不为0,就说明只出现了一次的数字在该位上的值就是1, 使用或运算将结果拼在一起,就是最后的答案。时间复杂度O(n), 空间复杂度O(1)。

代码:

public int singleNumber(int[] nums) {
    int result = 0;
    for (int i = 0; i < 32; i++) {
        int temp = 0;
        for (int n : nums) {
            temp += ((n >> i) & 1);
        }
        result |= ((temp % 3) << i);
    }
    return result;
}