ARTS 第四周

228 阅读3分钟

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

medium.com/palantir/co…

包括以下几个方面:

  • 为什么以及何时进行代码审查
  • 准备代码以供审核
  • 执行代码审查
    • 设计原理及实现
    • 是否有抽象
    • 是否考虑了异常
    • 与当前系统是否一致
    • 并发问题等
  • 代码审查示例

Tip

  • 平常的确要有意识做编程练习。除了常用数据结构。其它像字典树,背包问题(包括01背包, 完全背包,多重背包)要有计划的练习。

Share

背包问题处理步骤:

问题描述:有n 个物品,它们有各自的重量和价值,现有给定容量的背包,如何让背包里装入的物品具有最大的价值总和。

根据动态规划处理步骤:

  1. 把背包问题抽象化(X1,X2,…,Xn,其中Xi取0或1,表示第i个物品选或不选),Vi表示第i个物品的价值,Wi表示第i个物品的体积(重量);
  2. 建立模型,即求max(V1X1+V2X2+…+VnXn);
  3. 约束条件,W1X1+W2X2+…+WnXn<capacity;
  4. 定义V(i,j):当前背包容量 j,前 i 个物品最佳组合对应的价值;
  5. 寻找递推关系式,面对当前商品有两种可能性:  一,包的容量比该商品体积小,装不下,此时的价值与前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背包和完全背包。 多重背包及后面的还需要进一步学习。