找出只出现一次的两个数字,其余数字出现2次,
思路:
第一步:利用分治的思想先将两个出现一次的数字找出来,
第二步:然后将整体分解成某一位是0和1的两组数字,
第三步:然后在分别进行异或就可以了
具体过程如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void FindTwoNum(int arr[], int size, int* num1, int* num2){
//首先找到数组中出现一次的两个数
int ret = 0;
for (int i = 0; i < size; i++){
ret ^= arr[i];
}
//找到一个为1 的二进制位
int pos = 0;//pos 位置就是二进制位1 的位置
for (int pos = 0; pos < 32; pos++){
if ((ret &(1 << pos)) != 0){
break;
}
}
*num1 = 0;
*num2 = 0;
for (int i = 0; i < size; i++){
if (arr[i] & (1<<pos) == 1) {
//根据pos位置分为1
*num1 ^= arr[i];
}
else {
//根据pos位置分为0
*num2 ^= arr[i];
}
}
}
int main(){
int num1 = 0;
int num2 = 0;
int arr[] = { 1, 1, 2, 3, 2, 4 };
//int size = sizeof(arr) / sizeof(arr[0]);
FindTwoNum(arr, 6, &num1, &num2);
printf("两个数字分别是: num1=%d num2=%d\n", num1, num2);
system("pause");
return 0;
}
**运行结果: **
c++, 先找出只出现一次的两个数的异或值, 再将原数组分成两组(通过一个为1的标志位来决定),分别找出只出现一次的数(再异或一次)
class Solution {
public:
vector<int> singleNumber(vector<int>& nums) {
//第一步:先找到只出现一次的两个数
int ret = 0;
for (int i = 0; i < nums.size(); i++) {
ret ^= nums[i];
}
//第二步: 找到标志位为1的位置,用来区分最后一位是0(将这类数分一组)和最后一位是1(这一组的最后一位都是1)
ret &= (~ret) + 1;
int nums1 = 0;
int nums2 = 0;
//第三步: 遍历循环 ,分成两组之后,然后再各自进行异或处理
for (int i = 0; i < nums.size(); i++) {
if ((ret & nums[i]) == 1) { //这里有坑!记得一定要用括号把&括上:(ret & nums[i]),然后再==啊!
nums1 ^= nums[i];
}
else {
nums2 ^= nums[i];
}
}
return{ nums1, nums2 };
}
};
第一步:
把所有的元素进行异或操作,最终得到一个异或值。因为是不同的两个数字,所以这个值必定不为0;
for (int i=0;i<nums.size();i++ ) {
ret ^= nums[i];
}
第二步:
取异或值最后一个二进制位为1的数字作为ret,如果是1则表示两个数字在这一位上不同。
ret &= (~ret)+1;
第三步:
通过与这个ret进行与操作,如果为0的分为一个数组,为1的分为另一个数组。这样就把问题降低成了:“有一个数组每个数字都出现两次,有一个数字只出现了一次,求出该数字”。对这两个子问题分别进行全异或就可以得到两个解。也就是最终的数组了。
for (int i=0;i<nums.size();i++ ) {
if ((ret & nums[i]) == 0 ) {
nums1 ^= nums[i];
} else {
nums2 ^= nums[i];
}
}
return {nums1,nums2};