zoukankan      html  css  js  c++  java
  • LeetCode 笔记27 Two Sum III

    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还没有很多人提交哟:>

  • 相关阅读:
    最近碰到的一些问题
    CF #365 703D. Mishka and Interesting sum
    CF 690C3. Brain Network (hard) from Helvetic Coding Contest 2016 online mirror (teams, unrated)
    Mac Hadoop的安装与配置
    pyenv的安装和使用
    tmux简要介绍
    将本地的项目通过SVN还原到某一版本,并将SVN服务器上的项目也还原到这一版本
    Tomcat7解决中文乱码
    解决tomcat7控制台中文乱码问题
    JDK环境变量配置,实现多个版本的JDK环境变量任意切换配置(Windows7 / Windows10 )
  • 原文地址:https://www.cnblogs.com/lichen782/p/4348567.html
Copyright © 2011-2022 走看看