acwing-14

acwing-14

数组中唯一只出现一次的数字(困难)

在一个数组中除了一个数字只出现一次之外,其他数字都出现了三次。

请找出那个只出现一次的数字。

你可以假设满足条件的数字一定存在。

思考题:

  • 如果要求只使用 O(n) 的时间和额外 O(1) 的空间,该怎么做呢?
样例
输入:[1,1,1,2,2,2,3,4,4,4]

输出:3
  • 因为每个数字都只出现三次,所以倘若我们通过计算元素(以二进制表示)中每一位出现1的个数,通过模3取余得出的就是只出现一次的元素(以二进制表示)中对应位上的值,这样我们便可得出计算结果
  • 因为int是32位整形数,所以总体的算法复杂度为O(32n),因为是int,所以算法复杂度是大于**O(nlogn)**的
class Solution {
public:
    int findNumberAppearingOnce(vector<int>& nums) {
        int cnt=0,res=0;
        for(int i=31;i>=0;i--){
            for(int j=0;j<nums.size();j++){
                if((nums[j]&(1<<i))==1<<i)cnt++;
            }
            res=res*2+cnt%3;          
            cnt=0;
        }
        return res;
    }
};
  • 优化算法:
class Solution {
public:
    int findNumberAppearingOnce(vector<int>& nums) {
        int one=0,two=0;
        for(int i=0;i<nums.size();i++){
            one=(one^nums[i])&~two;
            two=(two^nums[i])&~one;
        }
        return one;
    }
};

在这里插入图片描述

  • 该代码形成了一个状态机,

  • 异或运算是对于每一位的异或运算,其实变相的承担了32位操作。

  • 上述的操作中两个数分别为onetwo(二进制表示)中每一位上的状态变化,通过两个表达式

    one=(one^nums[i])&~two;
    two=(two^nums[i])&~one;
    

    构建了状态机,其实只要关心第一位(one)就可以了,one每次针对异或1操作,其实和模3取余的效果是一样的

  • 这样one的其中的32位均是实现了模3取余的效果,所以结果的值为one

和为S的两个数字(简单)

输入一个数组和一个数字s,在数组中查找两个数,使得它们的和正好是s。

如果有多对数字的和等于s,输出任意一对即可。

你可以认为每组输入中都至少含有一组满足条件的输出。

样例
输入:[1,2,3,4] , sum=7

输出:[3,4]
  • 通过建立哈希表的方式,判断target-nums[i]是否存在,存在得到值target-nums[i],nums[i]
class Solution {
public:
    vector<int> findNumbersWithSum(vector<int>& nums, int target) {
        map<int,bool> hap;
        for(int i=0;i<nums.size();i++){
            hap[nums[i]]=true;
            if(hap[target-nums[i]]==true)return vector<int> {target-nums[i],nums[i]};
        }
    }
};

和为S的连续正数序列(中等)

输入一个正数s,打印出所有和为s的连续正数序列(至少含有两个数)。

例如输入15,由于1+2+3+4+5=4+5+6=7+8=15,所以结果打印出3个连续序列1~5、4~6和7~8。

样例
输入:15

输出:[[1,2,3,4,5],[4,5,6],[7,8]]
  • 采用双指针,i j 均从1开始
  • j指针不断向后推进直至遇到i—j的连续正整数序列之和大于等于sum
  • 如果结果等于于sum,并且j>i,将结果填入结果集中,如果结果大于sum,将i指针向后推进,返回上一步操作
  • 直到i的值为sum,算法结束
class Solution {
public:
    vector<vector<int> > findContinuousSequence(int sum) {
        vector<vector<int>> res;
        int i=1,j=1,s=1;
        for(i=1;i<=sum;i++){
            while(s<sum){s=s+(++j);}
            if(s==sum && j-i>0){
                vector<int> ans;
                for(int k=i;k<=j;k++)ans.push_back(k);
                res.push_back(ans);
            }
            s-=i;
        }
        return res;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值