Algorithm
-
给定整数m以及n个数字A1,A2,...An,将数列A中所有元素两两异或,共能得到n(n-1)/2个结果,请求出这些结果中大于m的有多少个。
-
最原始的算法不出意外timeout。
static int operation(int value, int[] digits) {
int cnt = 0;
for (int i = 0; i < digits.length - 1; i++) {
for (int j = i + 1; j < digits.length; j++) {
if ((digits[i] ^ digits[j]) > value) {
cnt++;
}
}
}
return cnt;
}
找了一下 通过字典树来解决。 将n个数字分别转换为二进制形式存储到Trie树中,比较a[i]元素和m对应的二进制的每一位上的数字,做相应的处理:
| m bit | 0 | 0 | 1 | 1 |
|---|---|---|---|---|
| a[i] bit | 0 | 1 | 0 | 1 |
| a[i]^a[j]>m a[j]bit | 为1一定大于m。 为0继续处理。 | a[j]bit为0一定大于m。为1继续处理。 | 继续bit为1的处理 | 继续bit为0的处理。 |
public class Main {
private static class TrieTree {
public TrieTree[] next = new TrieTree[2];
public long cnt = 1;
}
private static TrieTree buildTrieTree(int[] a) {
TrieTree root = new TrieTree();
for (int i = 0; i < a.length; i++) {
int value = a[i];
TrieTree current = root;
current.cnt++;
for (int shift = 31; shift >= 0; shift--) {
int tag = (value >> shift) & 1;
if (current.next[tag] == null) {
current.next[tag] = new TrieTree();
} else {
current.next[tag].cnt++;
}
current = current.next[tag];
}
}
return root;
}
private static long queryTrieTree(TrieTree root, int elem, int m, int depth) {
if (root == null) {
return 0;
}
TrieTree current = root;
for (int i = depth; i >= 0; i--) {
int elemBit = (elem >> i) & 1;
int mBit = (m >> i) & 1;
if (elemBit == 1 && mBit == 1) {
if (current.next[0] == null) {
return 0;
}
current = current.next[0];
} else if (elemBit == 0 && mBit == 1) {
if (current.next[1] == null) {
return 0;
}
current = current.next[1];
} else if (elemBit == 1 && mBit == 0) {
long p = queryTrieTree(current.next[1], elem, m, i - 1);
long q = current.next[0] != null ? current.next[0].cnt : 0;
return p + q;
} else if (elemBit == 0 && mBit == 0) {
long p = queryTrieTree(current.next[0], elem, m, i - 1);
long q = current.next[1] != null ? current.next[1].cnt : 0;
return p + q;
}
}
return 0;
}
public static long solve(int[] a, int m) {
TrieTree trieTree = buildTrieTree(a);
long ret = 0;
for (int i = 0; i < a.length; i++) {
ret += queryTrieTree(trieTree, a[i], m, 31);
}
return ret/2;
}
Review
包括以下几个方面:
- 为什么以及何时进行代码审查
- 准备代码以供审核
- 执行代码审查
- 设计原理及实现
- 是否有抽象
- 是否考虑了异常
- 与当前系统是否一致
- 并发问题等
- 代码审查示例
Tip
- 平常的确要有意识做编程练习。除了常用数据结构。其它像字典树,背包问题(包括01背包, 完全背包,多重背包)要有计划的练习。
Share
背包问题处理步骤:
问题描述:有n 个物品,它们有各自的重量和价值,现有给定容量的背包,如何让背包里装入的物品具有最大的价值总和。
根据动态规划处理步骤:
- 把背包问题抽象化(X1,X2,…,Xn,其中Xi取0或1,表示第i个物品选或不选),Vi表示第i个物品的价值,Wi表示第i个物品的体积(重量);
- 建立模型,即求max(V1X1+V2X2+…+VnXn);
- 约束条件,W1X1+W2X2+…+WnXn<capacity;
- 定义V(i,j):当前背包容量 j,前 i 个物品最佳组合对应的价值;
- 寻找递推关系式,面对当前商品有两种可能性: 一,包的容量比该商品体积小,装不下,此时的价值与前i-1个的价值是一样的,即V(i,j)=V(i-1,j); 二,还有足够的容量可以装该商品,即V(i,j)=max{V(i-1,j),V(i-1,j-w(i))+v(i) }
这篇文章讲的很好:blog.csdn.net/yandaoqiush… 目前明白了01背包和完全背包。 多重背包及后面的还需要进一步学习。