剑指 Offer 56 - I. 数组中数字出现的次数 | 算法

87 阅读2分钟

剑指 Offer 56 - I. 数组中数字出现的次数

一个整型数组 nums 里除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。
要求时间复杂度是O(n),空间复杂度是O(1)。


示例 1:

输入:nums = [4,1,4,6]
输出:[1,6][6,1]
示例 2:

输入:nums = [1,2,10,4,1,4,3,3]
输出:[2,10][10,2]

限制:
2 <= nums.length <= 10000

解题思路

leetcode.cn/problems/sh…

代码实现

class Solution:
    def singleNumbers(self, nums: List[int]) -> List[int]:
        res =  0
        a = 0
        b = 0
        for num in nums:
            res ^= num

        h = 1
        while (res &  h == 0):
            h <<= 1
        for num in nums:
                if (h & num == 0):
                    a ^= num
                else:
                    b ^= num

        return [a, b]

137. 只出现一次的数字 II

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

你必须设计并实现线性时间复杂度的算法且不使用额外空间来解决此问题。

示例 1:

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

示例 2:

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

提示:

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

解题思路

leetcode.cn/problems/si…

代码实现

var singleNumber = function(nums) {
    let res = 0
    for (let  i = 0; i < 32; i++){
        let count = 0
        for (let j = 0; j < nums.length; j++){
            if ((nums[j] >>  i & 1) == 1){
                count++
            }
        }
        if (count % 3 != 0){
            res = res | 1 << i
        }
    }
    return res
};

645. 错误的集合

集合 s 包含从 1 到 n 的整数。不幸的是,因为数据错误,导致集合里面某一个数字复制了成了集合里面的另外
一个数字的值,导致集合 丢失了一个数字 并且 有一个数字重复 。

给定一个数组 nums 代表了集合 S 发生错误后的结果。

请你找出重复出现的整数,再找到丢失的整数,将它们以数组的形式返回。


示例 1:

输入:nums = [1,2,2,4]
输出:[2,3]
示例 2:

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

提示:
2 <= nums.length <= 104
1 <= nums[i] <= 104

方法1:排序

将数组排序之后,比较每对相邻的元素,即可找到错误的集合。 寻找重复的数字较为简单,如果相邻的两个元素相等,则该元素为重复的数字。 寻找丢失的数字相对复杂,可能有以下两种情况: 如果丢失的数字大于 1 且小于 n,则一定存在相邻的两个元素的差等于 2,这两个元素之间的值即为丢失的数字; 如果丢失的数字是 1 或 nn,则需要另外判断。 为了寻找丢失的数字,需要在遍历已排序数组的同时记录上一个元素,然后计算当前元素与上一个元素的差。考虑到丢失的数字可能是 1,因此需要将上一个元素初始化为 0。 当丢失的数字小于 n 时,通过计算当前元素与上一个元素的差,即可得到丢失的数字; 如果 nums[n-1] =n,则丢失的数字是 nn。

var findErrorNums = function(nums) {
    const errorNums = new Array(2).fill(0)
    const n = nums.length
    nums.sort((a,b) => a - b)
    let prev = 0
    for (let i = 0; i < n; i++){
        const curr = nums[i]
        if(curr === prev){
            errorNums[0] = prev
        } else if (curr - prev > 1){
            errorNums[1] = prev + 1
        }
        prev = curr
    }
    if (nums[n - 1] !== n){
        errorNums[1] = n
    }
    return errorNums
};

方法2:哈希表

重复的数字在数组中出现 2 次,丢失的数字在数组中出现 0次,其余的每个数字在数组中出现 1 次。因此可以使用哈希表记录每个元素在数组中出现的次数,然后遍历从 1 到 n 的每个数字,分别找到出现 2 次和出现 0 次的数字,即为重复的数字和丢失的数字。

var findErrorNums = function(nums) {
    const errorNums = new Array(2).fill(0)
    const n = nums.length
    const map = new Map()
    for (const num of nums){
        map.set(num, (map.get(num)  || 0) + 1)
    }
    for (let i = 1; i<= n; i++){
        const count = map.get(i) || 0
        if (count === 2){
            errorNums[0] = i
        }else if (count === 0){
            errorNums[1] = i
        }
    }
    return errorNums
};

260. 只出现一次的数字 III

给你一个整数数组 nums,其中恰好有两个元素只出现一次,其余所有元素均出现两次。 
找出只出现一次的那两个元素。你可以按任意顺序 返回答案。

你必须设计并实现线性时间复杂度的算法且仅使用常量额外空间来解决此问题。

示例 1:

输入:nums = [1,2,1,3,2,5]
输出:[3,5]
解释:[5, 3] 也是有效的答案。
示例 2:

输入:nums = [-1,0]
输出:[-1,0]
示例 3:

输入:nums = [0,1]
输出:[1,0]


提示:
2 <= nums.length <= 3 * 104
-231 <= nums[i] <= 231 - 1
除两个只出现一次的整数外,nums 中的其他数字都出现两次
var singleNumber = function(nums) {
    let  ret= 0
    let a = 0, b = 0
    for (let n of nums){
        ret ^= n
    }
    h = 1
    while((ret & h) == 0) {
        h <<= 1
    }
    for (let n of nums){
        if ((h & n) == 0) {
            a ^= n
        }else {
            b ^= n
        }
    }
    return [a, b]

};