力扣 算法学习思路和题解 剑指 Offer 03. 数组中重复的数字

剑指 Offer 03. 数组中重复的数字

紫愿__人间尽好,一个致力于大二暑假进厂实习的少年,写作于2022/1/22

仅作为学习交流使用,原始题目来源力扣

题目描述

原始题目:找出数组中重复的数字。

在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。

限制条件:2 <= n <= 100000

初步思路

基本思想是类似于hash table,因为数值范围在0 ~ n - 1,那么就可以与数组索引一一对应。

基于以上观点,可得算法:

  1. 获取最大的可能达到的值max_value = n - 1;
  2. 为保护原始数组,深拷贝出一份数据_nums
  3. 若max_value != 0,则将max_value向右移一位,digits++;
  4. 将1向左移digits位,即可得到一个标志位的值。
  5. i从0开始,到nums.size()为止:
    1. 如果_nums[i]去除标志位后的索引指向的向量元素标志位为1,则直接返回_nums[i]标志位置零的值。
    2. _nums[i]去除标志位后的索引指向的向量元素标志位置为1。
解题代码
int findRepeatNumber(vector<int>& nums) {
    unsigned long long max_value = nums.size() - 1;
    int digits = 0; // 记录总共有多少位二进制。
    int scale = 1;  // 比数组最大元素能取到的二进制最高位还高一位的2的倍数。
    vector<int> _nums(nums);
    while(max_value){
        digits++;
        max_value >>= 1;
    }
    scale <<= digits;
    max_value = nums.size() - 1;

    for (int i = 0; i <= max_value; i++){
        if (_nums[_nums[i] & (scale - 1)] >> digits){
            return _nums[i] & (scale - 1);
        }
        _nums[_nums[i] & (scale - 1)] |= scale;
    }

    return -1;
}
执行成果

初步思路成果截图

优化方案

直接在原始向量上进行修改,找到之后在返回之前,遍历数组,将所有值的标志位都置为0。

代码实现
int findRepeatNumber(vector<int>& nums) {
    unsigned long long max_value = nums.size() - 1;
    int digits = 0; // 记录总共有多少位二进制。
    int scale = 1;  // 比数组最大元素能取到的二进制最高位还高一位的2的倍数。
    int target; // 将结果保存进来。
    while(max_value){
        digits++;
        max_value >>= 1;
    }
    scale <<= digits;
    max_value = nums.size() - 1;

    for (int i = 0; i <= max_value; i++){
        if (nums[nums[i] & (scale - 1)] >> digits){
            target = nums[i] & (scale - 1);
            break;
        }
        nums[nums[i] & (scale - 1)] |= scale;
    }

    for (int i = 0; i <= max_value; i++){
        nums[i] &= scale - 1;
    }

    return target;
}
成果截图

优化成果截图

可以看到,对比还是蛮大的,这里又重新遍历了一次数组,性能有一定的削减,不过考虑到此算法保证了数组元素的不变性,还是很值得推荐的。

紫愿_人间尽好,在一个致力于大二暑假进厂实习的少年,写作于2022/1/22

此文仅作为学习交流使用

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

紫愿_人间尽好

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值