1、题目:
题目描述
给定整数m以及n各数字A1,A2,..An,将数列A中所有元素两两异或,共能得到n(n-1)/2个结果,请求出这些结果中大于m的有多少个。
输入描述:
第一行包含两个整数n,m.
第二行给出n个整数A1,A2,...,An。
数据范围
对于30%的数据,1 <= n, m <= 1000
对于100%的数据,1 <= n, m, Ai <= 10^5
输出描述:
输出仅包括一行,即所求的答案
示例1
输入
3 10
6 5 10
输出
2
2、思想:
首先想到的是暴力法破解,但是看到给的的测试数据范围就知道会超时,但是还是先写了这个算法,就想知道通过率可以有多少;然后看了字典树方法,也基本学会了,虽然还是不够熟练,然而因为字典树核心思想是空间换时间,所以又超内存了...呃,目前想不出方法了,昨天晚上就看,今天还是没做出来,就先这样吧,等后期第二波刷题时候,看看左神的书也许会有新变化。
3、code:两个都没有a过,暴力法超时,通过率50%;字典树法超内存,通过率70%
(1)暴力法:
package schooloffer17;
import java.util.Scanner;
/**
* @Author: cxh
* @CreateTime: 17/11/20 15:54
* @ProjectName: JavaBaseTest
* <异或></>
*/
public class XOR {
public static void main(String[] args) {
int n,m;
Scanner scanner=new Scanner(System.in);
while (scanner.hasNext()){
n=scanner.nextInt();
m=scanner.nextInt();
int[] number=new int[n];
for(int i=0;i<n;i++)
number[i]=scanner.nextInt();
int res=0;
for(int i=0;i<n-1;i++){
for(int j=i+1;j<n;j++){
res+=(number[i]^number[j])>m?1:0;
}
}
System.out.println(res);
}
}
}
(2)字典树法:
package schooloffer17;
import java.util.Scanner;
/**
* @Author: cxh
* @CreateTime: 17/11/20 15:54
* @ProjectName: JavaBaseTest
* <异或></>
* 关键算法:字典树TrieTree的应用
*/
public class XOR {
private static class TrieTree{
TrieTree[] next=new TrieTree[2];//next[0]表示左节点, next[1]表示右节点.
int count=1;//表示有多少个数的在形成01字符串表达式的过程中,经过了这个节点
}
public static void main(String[] args) {
int n,m;
Scanner scanner=new Scanner(System.in);
while (scanner.hasNext()){
n=scanner.nextInt();
m=scanner.nextInt();
int[] number=new int[n];
for(int i=0;i<n;i++)
number[i]=scanner.nextInt();
//建树
TrieTree root=builderTree(number);
int res=0;//记录结果值
for(int i=0;i<n;i++){
//查找TrieTree树,并进行比较
res+=searchTrieTree(root,number[i],m,31);
}
System.out.println(res/2);
}
}
/**
* 建树
* 这是一棵二叉树,高度最高为33(最深处:33个节点,边32条,因为字典树定义就是:节点不存储数据,边才表示0或者1)
* @param a
*/
private static TrieTree builderTree(int[] a){
TrieTree root=new TrieTree();
for(int i=0;i<a.length;i++){
TrieTree curr=root;
for(int j=31;j>=0;j--){
int digit=(a[i]>>j) & 1;
if(curr.next[digit]==null){
curr.next[digit]=new TrieTree();//count=1是初始值,故这里就不用再new之后为count赋值为1了
}else{
curr.next[digit].count++;
}
curr=curr.next[digit];
}
}
return root;
}
/**
* 搜索查找字典树
* @param root 字典树根
* @param a 要比较的元素
* @param m 输入的比较值
* @param move 需要右移的位数
* @return
*/
private static int searchTrieTree(TrieTree root,int a,int m,int move){
if(root==null)
return 0;
TrieTree curr=root;
for(int i=move;i>=0;i--){
int aDigit=(a>>i) & 1;
int mDigit=(m>>i) & 1;
if(aDigit==0 && mDigit==0){
int x=searchTrieTree(curr.next[0],a,m,i-1);
int y=curr.next[1]==null?0:curr.next[1].count;
return x+y;
}else if(aDigit==0 && mDigit==1){
if(curr.next[1]==null)
return 0;
curr=curr.next[1];
}else if(aDigit==1 && mDigit==0){
int x=curr.next[0]==null?0:curr.next[0].count;
int y=searchTrieTree(curr.next[1],a,m,i-1);
return x+y;
}else{
if(curr.next[0]==null)
return 0;
curr=curr.next[0];
}
}
return 0;
}
}