算法很美-位运算-找出唯一成对的数

上一目录:算法很美

1. 题目:

1-1000这1000个数放在含有1001个元素的数组中,只有唯一的一个元素值重复,其他均只出现一次。每个数组元素只能访问一次,设计一个算法,将它找出来;你能否设计一个算法实现?

2. 异或思路:

  • 异或的基本公式是A^A=0, A ^ 0 = A, 所以 A ^ A ^ A = A,这样继续类推, A ^ A ^ B ^ B ^ B ^ C ^ C=B。

  • 解题思路如下:
    这1001个元素有999个是不重复的,把他们假设是A组元素,也就是说A组中元素只出现了1次,只有一个B元素出现了两次,那么我们可以使用1000个不重复的元素对1001个元素,包括A和B组元素进行异或运算,最终使得每一个A元素的数量是2,每一个B元素的数量是3,这样根据1中的规律,最终我们得到的是B元素的值,也就是我们需要寻找的重复元素

  • 代码如下:

package com.example.algorithm.demo.c2;

import java.util.Random;

/**
 * 找出唯一成对的数
 */
public class c21 {
public static void main(String[]args){
    //第一步,构造符合条件的数组,即A+B=N,其中B=2,A=N-2,且存在1到N-1个不重复元素
    //小数验证运算
    int N = 1001;
    //放在N位数的数组中
    int[] arr = new int[N];
    //先把1到N-1填充到前N个数组元素中
    for(int i = 0; i < arr.length-1; i ++){
        arr[i] = i+1;
    }
    //最后一个数是随机数,范围是在[1,N-1]之间
    //nextInt()返回的是[0,N)之间的整数,加一后返回[1,N)之间的整数
    arr[arr.length-1]=new Random().nextInt(N-1)+1;

    //进行异或运算得到最终的B值
    //首先对数组arr中的N个元素进行异或运算
    int x1 = 0;
    for(int i = 0; i < arr.length; i ++){
        x1=(x1^arr[i]);
    }
    //在将得到的异或式x1与1到N-1个元素的异或结果继续异或
    for(int i = 1; i < N; i ++){
        x1=(x1^i);
    }
    //输出重复的值
    System.out.println("重复的值:"+arr[arr.length-1]);
    //最后输出得到的结果,也就是B的值
    System.out.println("B:"+x1);
}
}

3. 暴力解决思路(使用辅助存储空间)

  • 假设数组arr符合题目要求的构造条件,我们设计另一个辅助数组helper,对arr数组进行遍历,每次循环对helper[arr[i]]做加一操作,那么最后下标是A组元素的helper数组的值都是1,下标B元素的helper数组的值是2,所以只需加一个判断条件,得到值大于1的helper数组元素,输出这个元素下标,也就是B元素
  • 代码如下:
package com.example.algorithm.demo.c2;

import java.util.Random;

/**
 * 找出唯一成对的数
 */
public class c21 {
public static void main(String[]args){
    //第一步,构造符合条件的数组,即A+B=N,其中B=2,A=N-2,且存在1到N-1个不重复元素
    //小数验证运算
    int N = 1001;
    //放在N位数的数组中
    int[] arr = new int[N];
    //先把1到N-1填充到前N个数组元素中
    for(int i = 0; i < arr.length-1; i ++){
        arr[i] = i+1;
    }
    //最后一个数是随机数,范围是在[1,N-1]之间
    //nextInt()返回的是[0,N)之间的整数,加一后返回[1,N)之间的整数
    arr[arr.length-1]=new Random().nextInt(N-1)+1;

    //进行异或运算得到最终的B值
    //首先对数组arr中的N个元素进行异或运算
    int x1 = 0;
    for(int i = 0; i < arr.length; i ++){
        x1=(x1^arr[i]);
    }
    //在将得到的异或式x1与1到N-1个元素的异或结果继续异或
    for(int i = 1; i < N; i ++){
        x1=(x1^i);
    }
    System.out.println("===============异或破解=====");
    //输出重复的值
    System.out.println("重复的值:"+arr[arr.length-1]);
    //最后输出得到的结果,也就是B的值
    System.out.println("异或破解B:"+x1);
    System.out.println("===============暴力破解=====");
    //创建辅助数组,因为按照思路,下标最大是N-1,所以长度是N刚刚好
    int[] helper = new int[N];
    //遍历赋值得出B元素
    for (int i = 0; i < N; i ++){
        helper[arr[i]] ++;
        if (helper[arr[i]] > 1 ){
            System.out.println("暴力破解B:"+arr[i]);
            break;
        }
    }

}
}

感觉真不错,脑子还是可以的

原创文章 243 获赞 156 访问量 2万+

猜你喜欢

转载自blog.csdn.net/weixin_43404791/article/details/105885598