Design and implement a TwoSum class. It should support the following operations: add and find.

add - Add the number to an internal data structure.
find - Find if there exists any pair of numbers which sum is equal to the value.

这个解法很容易想到,但很容易超时。

基本来说有这样几个途径去解。

第一种,使用一个数组去存所有加入的元素,使用一个Set去存所有的和。在实现Find的时候,遍历数组,把能够得到的和都加到set中去。这样,find的时间复杂度是O(1)了,因为只需要判断value是否在集合里面,但是add就变成了O(n)。实践证明这是行不通的。

第二种,还是使用一个数组去存元素,但是每次加入的时候保持数组有序,这样虽然可以通过二分查找找到插入点,但是插入本身,由于是在数组中,复杂度就变成O(n)了。在实现Find的时候,使用TwoSum标准算法(用两个指针,一前一后遍历)。所以这个也没有好多少,还是会超时。

第三种,不要使用数组了。使用一个Search Tree来存放元素。这样在add的时候可以基本保证O(logn)。

Find怎么办呢?

其实也可以采用TwoSum的那个标准算法,但是需要在TreeNode里面存放一个pre和next指针,分别是排序后的,该节点的前一个和后一个元素。这样你远看是一颗树,近看是双向链表。

在二叉排序树中插入一个节点大家都会,要注意的是如何在插入的过程中,记录pre和next。其实只要是向右搜索,我们就给pre赋值,向左搜索就给next赋值就可以了。

哦,对了,还要在插入过程中注意update 双向链表的head和tail,这个也很容易,只要插入后发现pre是null,那么这个节点肯定是head嘛,next是null就是tail咯。

代码是这个。

public class TwoSumDS {

    private TreeNode root;
private TreeNode head;
private TreeNode tail; //private Set<Integer> seenSum = new HashSet<>(); public void add(int number) {
if (root == null) {
root = new TreeNode(number);
head = tail = root;
} else {
insertIntoTree(number);
}
} public boolean find(int value) {
{
if (head != null && tail != null && head != tail) {
TreeNode p = head, q = tail;
while (p != q) {
int sum = p.val + q.val;
//seenSum.add(sum);
if (sum > value) {
q = q.pre;
} else if (sum < value) {
p = p.next;
} else {
return true;
}
}
}
}
return false;
} private void insertIntoTree(int val) {
TreeNode p = root;
TreeNode pre = null;
TreeNode next = null;
while (true) {
//seenSum.add(val + p.val);
if (val > p.val) {
pre = p;
if (p.right != null) {
p = p.right;
} else {
p.right = new TreeNode(val);
insertInToChain(p.right, pre, next);
break;
}
} else {
next = p;
if (p.left != null) {
p = p.left;
} else {
p.left = new TreeNode(val);
insertInToChain(p.left, pre, next);
break;
}
}
}
} private void insertInToChain(TreeNode n, TreeNode pre, TreeNode next) {
if (pre != null) {
pre.next = n;
} else {
head = n;
}
if (next != null) {
next.pre = n;
} else {
tail = n;
}
n.pre = pre;
n.next = next;
} private static class TreeNode {
int val;
TreeNode right;
TreeNode left;
TreeNode pre;
TreeNode next;
TreeNode(int val) {
this.val = val;
}
} public static void main(String[] args) {
TwoSumDS ts = new TwoSumDS();
ts.add(1);
ts.add(3);
ts.add(5);
System.out.println(ts.find(4));
System.out.println(ts.find(7));
}
}

注意到撸主注释的部分,有一个优化。就是在插入和搜索过程中,沿途找到的sum我们缓存起来,下次说不定可以用。Find的之前可以先在seenset里面看看。

不过这个优化导致了超时,所以就去掉了。看了一下Java doc,并没有gurantee HashSet的存放操作是O(1)的。

看来Java还没有很多人提交哟:>

最新文章

  1. guava学习--File
  2. DDL和DML的定义和区别
  3. Linux启动Apache支持.htaccess伪静态文件方法
  4. Hook入门
  5. 利用Jmeter做接口测试
  6. [BZOJ1609] [Usaco2008 Feb] Eating Together麻烦的聚餐 (dp)
  7. Redis Error:/var/redis/run/redis_6379.pid exists, process is already running or crashed
  8. UNIX环境高级编程——标准I/O库
  9. 【一天一道LeetCode】索引目录 ---C++实现
  10. 铁大Facebook轻量化界面NABCD
  11. ELK大流量日志分析系统搭建
  12. Android中不显示标题
  13. 提取路由器固件中的squashfs
  14. java⑿
  15. VSCode一直弹框错误Linter pylint is not installed
  16. day 74 vue 2 axios数据请求 以及组件的学习
  17. 添加相应型号和头文件到Keil中
  18. 基于flex的不定个数的按钮组
  19. 如何去除decimal后面的零?
  20. 如何在Django1.6结合Python3.4版本中使用MySql

热门文章

  1. SQLAlchemy 做migration的时候 ValueError: too many values to unpack
  2. SAM4E单片机之旅——14、LCD之SMC的配置
  3. Profile 分析 Erlang 虚拟机源码时要注意的一个问题
  4. Effective Java 56 Adhere to generally accepted naming conventions
  5. Effective Java 73 Avoid thread groups
  6. SpringMVC4 + Spring + MyBatis3 基于注解的最简配置
  7. 用memoization优化递归算法[JS/PHP实现]
  8. 关于HADOOP HA 中DFSZKFC的理解
  9. codeforces 724
  10. Medial Queries的另一用法:实现IE hack的方法