哈希,LeetCode 2007. 从双倍数组中还原原数组

一、题目

1、题目描述

一个整数数组 original 可以转变成一个 双倍 数组 changed ,转变方式为将 original 中每个元素 值乘以 2 加入数组中,然后将所有元素 随机打乱 。

给你一个数组 changed ,如果 change 是 双倍 数组,那么请你返回 original数组,否则请返回空数组。original 的元素可以以 任意 顺序返回。

2、接口描述

python3
class Solution:
    def findOriginalArray(self, changed: List[int]) -> List[int]:
cpp
class Solution {
public:
    vector<int> findOriginalArray(vector<int>& changed) {

    }
};

3、原题链接

2007. 从双倍数组中还原原数组 - 力扣(LeetCode)


二、解题报告

1、思路分析

我们考虑将数组排序后会是什么样子?

a ... a  2a... 2a  c ... c  d ... d 2d ……

那么我们有一种O(nlogn)做法(也是我第一次做的时候的做法),将数组排序,然后哈希统计

然后从小到大遍历数组,用x排除2x,如果出现某个元素仍有剩余那就返回空,不然就是一个目标数组,我们在遍历的时候添加元素到返回数组即可

然后看到题解有O(n)做法

事实上不需要排序,只需哈希计数

我们发现我们只要拿到a,就能排除2a,4a……

那么我们哈希 统计后,遍历哈希表,如果x不存在x / 2在哈希表中,说明它可能是某个连续序列的起点,我们从x往下一直排除2x,4x……

如果存在cnt[x] > cnt[2x]就返回空数组

2、复杂度

时间复杂度: O(n)空间复杂度:O(n)

3、代码详解

python3
class Solution:
    def findOriginalArray(self, changed: List[int]) -> List[int]:
        mp = Counter(changed)
        cnt0 = mp.pop(0, 0) # default = 0,不存在0返回0
        if cnt0 & 1:
            return []
        ret = [0] * (cnt0 // 2)
        for x in mp:
            if x % 2 == 0 and x // 2 in mp:
                continue
            while x in mp:
                cnt = mp[x]
                if cnt > mp[x * 2]:
                    return []
                ret.extend([x] * cnt)
                if cnt < mp[x * 2]:
                    mp[x * 2] -= cnt
                    x *= 2
                else:
                    x *= 4
        return ret

        
cpp
class Solution {
public:
    vector<int> findOriginalArray(vector<int>& changed) {
        if(changed.size() & 1) return {};
        unordered_map<int, int> mp;
        int cnt0 = 0;
        for(auto x : changed) mp[x] ++, cnt0 += !x;
        if(cnt0 & 1) return {};
        mp.erase(0);
        vector<int> ret(cnt0 / 2);
        for(auto [k, _] : mp){
            int x = k;
            if(x & 1 || !mp.count(x / 2)){
                while(mp.count(x)){
                    int cnt = mp[x];
                    if(cnt > mp[x * 2]) return {}; 
                    ret.insert(ret.end(), cnt, x);
                    if(mp[x << 1] > cnt) mp[x << 1] -= cnt, x <<= 1;
                    else x <<= 2;
                }
            }
        }
        return ret;
    }
};

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

EQUINOX1

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

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

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

打赏作者

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

抵扣说明:

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

余额充值