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

上一目录:算法很美

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;
        }
    }

}
}

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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值