我是靠谱客的博主 留胡子蛋挞,最近开发中收集的这篇文章主要介绍【剑指Offer】数组中只出现一次的两个数字(其余数都出现两次)(普通排序 / 满足交换律的异或)题目描述解法,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

目录

  • 题目描述
  • 解法
    • 排序然后左右比较
    • 满足交换律的异或

题目描述

一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。

解法

排序然后左右比较

  1. 先将数组升序排序。
  2. 从第一个数开始,比较相邻两个数字xi,xi+1:如果相同,则往后移两位,继续比较;如果不同,则判断xi和前面数字是否也不同,xi+1和后面数字是否也不同,这样判断它数值的唯一性。
  3. 需要注意最后一个数字没参与比较,所以如果结果还差一个数,那就是差的最后这个数字。
  • 时间复杂度O(NlogN):N是数组大小,因为vector容器的排序是快排,最好、正常和平均时间复杂度都为O(nlogn),后面查找是O(N)
  • 空间复杂度O(1)
    【牛客】
class Solution {
public:
    void FindNumsAppearOnce(vector<int> data,int* num1,int *num2) {
        sort(data.begin(), data.end());
        int size = data.size();
        bool findflag1 = false, findflag2 = false;
        
        int i = 0;
        while( i<=size-2 && (!findflag1 || !findflag2) ){
            if( data[i] == data[i+1] ){
                i += 2;
                continue;
            }
            int j = i;
            //data[i]和前面的数组比较,如果不相同,说明data[i]不等于后面也不等于前面,是个特数
            if( i==0 || (i>=1 && data[i-1]!=data[i]) ){
                if( !findflag1 ){
                    *num1 = data[i];
                    findflag1 = true;
                    j++;
                }else if( !findflag2 ) {
                    *num2 = data[i];
                    findflag2 = true;
                    j++;
                }
            }
            //data[i+1]和后面的数组比较,如果不相同,说明data[i+1]不等于前面也不等于后面,是个特数
            if( i==(size-2) || (i <= size-3 && data[i+1] != data[i+2]) ){
                if( !findflag1 ){
                    *num1 = data[i+1];
                    findflag1 = true;
                    j++;
                }else if( !findflag2 ) {
                    *num2 = data[i+1];
                    findflag2 = true;
                    j++;
                }
            }
            i = j;
        }
        //最后一个数
        if( !findflag1 ){
            *num1 = data[size-1];
            findflag1 = true;
        }
        if( !findflag2 ){
            *num2 = data[size-1];
            findflag2 = true;
        }
    }
};

【leetcode】

class Solution {
public:
    vector<int> singleNumbers(vector<int>& nums) {
        vector<int> anws;
        sort(nums.begin(), nums.end());
        int size = nums.size();
        int i = 0;
        while( i<=size-2 && ( anws.size()<2 ) ){
            if( nums[i] == nums[i+1] ){
                i += 2;
                continue;
            }
            int j = i;
            //nums[i]和前面的数组比较,如果不相同,说明nums[i]不等于后面也不等于前面,是个特数
            if( i==0 || (i>=1 && nums[i-1]!=nums[i]) ){
                anws.push_back(nums[i]);
                j++;
            }
            //nums[i+1]和后面的数组比较,如果不相同,说明nums[i+1]不等于前面也不等于后面,是个特数
            if( i==(size-2) || (i <= size-3 && nums[i+1] != nums[i+2]) ){
                anws.push_back(nums[i+1]);
                j++;
            }
            i = j;
        }
        //最后一个数
        if( anws.size()<2 ){
            anws.push_back(nums[size-1]);
        }
        return anws;
    }
};

满足交换律的异或

参考了leetcode讨论区某个高赞回答

  1. 对所有数字进行异或操作:因为异或满足交换率,相同的数都异或为0抵消了,剩下两个独数,所以异或结果其实是两个独数的异或结果。异或结果肯定有某一位为1,不然都是0的话就是相同数(两个独数一个在此位为0,另一个为1)。
  2. 找到这个位(随便哪一位都可以)并设为mask:从最低位0001开始,如果和异或结果的相与结果为0,那就不断左移,往更高位0010找
  3. 按此位将所有数分成两组:用mask来对所有数相与,根据与结果是否为0来将数分为两组
  4. 分成两组后,组内所有数各自异或:相同的两个数异或肯定为0(而且分开的时候,相同的两个数必为一组),最后剩下的每组里就是我们要找的独数。
class Solution {
public:
    void FindNumsAppearOnce(vector<int> data,int* num1,int *num2) {
        //XOR是所有数字的异或结果:
        //因为异或具有交换性,相同的数都异或为0了,所以这个结果其实是两个独数的异或结果,
        int XOR = 0; 
        for( int i = 0; i < data.size(); i++ ){
            XOR ^= data[i];
        }
        //XOR一定不为0,被置1的位表示在这一位上两个独数是不同的(在这位上一个为0,另一个为1)
        //找出这一位(随便哪一位都可以)并设为mask
        int mask = 1; //从最低位开始
        while( (XOR & mask) == 0 ){ 
            mask <<= 1; //左移,继续往更高位找
        }
        //用mask来对所有数相与,可以根据结果是否为0将数分为两组,并且组内所有数的异或结果就是独数
        int group1 = 0, group2 = 0;
        for( int i = 0; i < data.size(); i++ ){
            if( (data[i] & mask) == 0 ){ //异或结果为0的组
                group1 ^= data[i]; //组内所有数进行异或操作,最后的异或结果只剩独数
            }else{//异或结果为1的组
                group2 ^= data[i]; 
            }
        }
        *num1 = group1;
        *num2 = group2;
    }
};

最后

以上就是留胡子蛋挞为你收集整理的【剑指Offer】数组中只出现一次的两个数字(其余数都出现两次)(普通排序 / 满足交换律的异或)题目描述解法的全部内容,希望文章能够帮你解决【剑指Offer】数组中只出现一次的两个数字(其余数都出现两次)(普通排序 / 满足交换律的异或)题目描述解法所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(76)

评论列表共有 0 条评论

立即
投稿
返回
顶部