leetcode 170: Two Sum III - Data structure design


leetcode 170: Two Sum III - Data structure design - 西施豆腐渣 - 博客频道 - CSDN.NET
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.
For example,
add(1); add(3); add(5);
find(4) -> true
find(7) -> false

X. https://blog.csdn.net/magicbean2/article/details/72910861
2、find优先:
    TwoSum() {
       
    }
   
    /** Add the number to an internal data structure.. */
    void add(int number) {
        for (int i = 0; i < nums.size(); ++i) {
            sums.insert(nums[i] + number);
        }
        nums.push_back(number);
    }
   
    /** Find if there exists any pair of numbers which sum is equal to the value. */
    bool find(int value) {
        return sums.find(value) != sums.end();
    }
private:
    vector<int> nums;
    unordered_set<int> sums;

https://leetcode.com/discuss/19515/my-solutions-java-and-python-time-for-add-time-for-find-space
O(1) time for add, O(n) time for find, O(n) space
I use HashMap to store times of number be added. When find be called, we iterate the keys of HashMap, then find another number minus by value. Then combine the detections together.
http://buttercola.blogspot.com/2015/08/leetcode-two-sum-iii-data-structure.html
    private Map<Integer, Integer> map = new HashMap<Integer, Integer>();
     
 public void add(int number) {
     if (map.containsKey(number)) {
         int val = map.get(number) + 1;
         map.put(number, val);
     } else {
         map.put(number, 1);
     }
 }
 public boolean find(int value) {
     if (map.isEmpty()) {
         return false;
     }
     Iterator it = map.entrySet().iterator();
     // Itearte over the set
     while (it.hasNext()) {
         Map.Entry pair = (Map.Entry) it.next();
         int firstKey =  (int) pair.getKey();
         int firstValue = (int) pair.getValue();
          
         int secondKey = value - firstKey;
          
         // 0 + 0 = 0
         if (firstKey == secondKey && firstValue >= 2) {
             return true;
         else if (firstKey != secondKey && map.containsKey(secondKey)) {
             return true;
         }
     }
     return false;
 }
Clean code: http://yuanhsh.iteye.com/blog/2186428
  1. Map<Integer, Integer> dict = new HashMap<Integer, Integer>();  
  2.   
  3. public void add(int number) {  
  4.     if (dict.containsKey(number)) {  
  5.         dict.put(number, dict.get(number) + 1);  
  6.     } else {  
  7.         dict.put(number, 1);  
  8.     }  
  9. }  
  10.   
  11. public boolean find(int value) {  
  12.     for (Integer key : dict.keySet()) {  
  13.         if (value - key == key) {  
  14.             if (dict.get(key) >= 2) {  
  15.                 return true;  
  16.             }  
  17.         } else if (dict.containsKey(value - key)) {  
  18.             return true;  
  19.         }  
  20.     }  
  21.   
  22.     return false;  
  23.  
  1. public class TwoSum {  
  2.     Map<Integer, Integer> map = new HashMap<Integer, Integer>();  
  3.       
  4.     public void add(int number) {  
  5.         if(map.containsKey(number)) {  
  6.             map.put(number, map.get(number) + 1);  
  7.         } else {  
  8.             map.put(number, 1);  
  9.         }  
  10.     }  
  11.   
  12.     public boolean find(int value) {  
  13.         for(int key : map.keySet()) {  
  14.             int another = value - key;  
  15.             if(another == key && map.get(key) > 1) {  
  16.                 return true;  
  17.             } else if(another != key && map.containsKey(another)) {  
  18.                 return true;  
  19.             }  
  20.         }  
  21.         return false;  
  22.     }  
  23. }  
https://leetcode.com/discuss/19562/java-solution-o-n-add-o-1-find-and-o-n-space
O(n) add, O(1) find
public class TwoSum { Map<Integer, Integer> numToCountMap = new HashMap<>(); Set<Integer> sums = new HashSet<>(); public void add(int number) { for (Integer ele : numToCountMap.keySet()){ sums.add(number + ele); } Integer counts = numToCountMap.get(number); counts = (counts == null) ? 1 : counts+1; numToCountMap.put(number, counts); } public boolean find(int value) { return sums.contains(value); } }

Use 2 hashsets. - we don't care the count.
void add(int number) { for(const auto& num:numSet) sumSet.insert(num+number); numSet.insert(number); } bool find(int value) { return sumSet.find(value)!=sumSet.end(); } private: unordered_set<int> numSet, sumSet;
http://www.1point3acres.com/bbs/forum.php?mod=viewthread&tid=159612&pid=2122139&page=1&extra=page%3D5%26filter%3Dsortid%26sortid%3D311#pid2122139
--> list is not good - as the data may contain duplicates
-> we don't need the count in the map.
public class TwoSumTest2 implements TwoSum{
    private HashMap<Integer, Integer> map;
    private ArrayList<Integer> list;
    int lastIndex;

    public TwoSumTest2(){
        map = new HashMap<Integer, Integer>();
        list = new ArrayList<Integer>();
        lastIndex = 0;
    }

    public void store(int input){
        list.add(input);
        for(int i =1; i<= lastIndex;i++){
        map.put(list.get(i)+input,1);
        }
        lastIndex++;
    }
.鐣欏璁哄潧-涓€浜�-涓夊垎鍦�
    public boolean test(int val){
        if (map.containsKey(val)){
        return true;
        }
        return false;
    }. 鍥磋鎴戜滑@1point 3 acres
}

Not good, just different:

https://leetcode.com/discuss/76823/beats-100%25-java-code
I found that using a count map alone is twice as slow. Do you have any idea why?

This is very interesting, using approach utilizing Map.Entry is good, such as https://leetcode.com/discuss/19515/my-solutions-java-and-python-time-for-add-time-for-find-space. but still performed much worse than using a list like this one.
I think it is due to HashSet iterator traversing overhead, comparing to good-old positional traversing.
Actually HashMap<Integer, Boolean> would do the job, no need of HashMap<Integer, Integer>

Map<Integer, Boolean> num2dupMap = new HashMap<Integer, Boolean>(); // Add the number to an internal data structure. public void add(int number) { // add number to a map, if already exist, set it to true num2dupMap.put(number, num2dupMap.containsKey(number)); } // Find if there exists any pair of numbers which sum is equal to the value. public boolean find(int value) { // for each of the number in the map, get the (value - number) // try to find (value - number) in the map // if it exits in the map, for(Entry<Integer, Boolean> entry: num2dupMap.entrySet()){ int num1 = entry.getKey(); int num2 = value - num1; if (num1 == num2 && entry.getValue()){ // 1. could be number2 = (value - number1) hence to make sure it not only // just found the original number, but a 2nd number of the same value, // we need to && map.get(number2) == true // then return true return true; } else if (num1 != num2 && num2dupMap.containsKey(num2)){ // 2. could be number2 != (value - number1), and if we `enter code here`found it, we // found a winner return true; } } return false; }
https://leetcode.com/discuss/52158/java-ac-solution-with-avl-tree
https://leetcode.com/discuss/oj/two-sum-iii-data-structure-design
You can further reduce the space complexity by not using the List list and use the keyset of Map to iterate over the added integers.
public class TwoSum { List<Integer> list = new ArrayList<Integer>(); Map<Integer, Integer> map = new HashMap<Integer, Integer>(); // Add the number to an internal data structure. public void add(int number) { list.add(number); if (map.containsKey(number)) map.put(number, map.get(number)+1); else map.put(number, 1); } // Find if there exists any pair of numbers which sum is equal to the value. public boolean find(int value) { for (int i = 0; i < list.size(); i++) { int num1 = list.get(i); int num2 = value - num1; if ((num1 == num2 && map.get(num1) > 1) || (num1 != num2 && map.containsKey(num2))) return true; } return false; }
https://leetcode.com/discuss/76146/trade-off-in-this-problem-should-be-considered
public class TwoSum { Set<Integer> sum; Set<Integer> num; TwoSum(){ sum = new HashSet<Integer>(); num = new HashSet<Integer>(); } // Add the number to an internal data structure. public void add(int number) { if(num.contains(number)){ sum.add(number * 2); }else{ Iterator<Integer> iter = num.iterator(); while(iter.hasNext()){ sum.add(iter.next() + number); } num.add(number); } } // Find if there exists any pair of numbers which sum is equal to the value. public boolean find(int value) { return sum.contains(value); } }

Extended: how about 3 sum or k sum.
-- use TreeMap<Integer, Integer> dict = new TreeMap<>(); ??

X. Binary Search Tree
https://www.bbsmax.com/A/1O5E9lAy57/
第一种,使用一个数组去存所有加入的元素,使用一个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咯。
  1. private TreeNode root;
  2. private TreeNode head;
  3. private TreeNode tail;
  4.  
  5. //private Set<Integer> seenSum = new HashSet<>();
  6.  
  7. public void add(int number) {
  8. if (root == null) {
  9. root = new TreeNode(number);
  10. head = tail = root;
  11. } else {
  12. insertIntoTree(number);
  13. }
  14. }
  15.  
  16. public boolean find(int value) {
  17. {
  18. if (head != null && tail != null && head != tail) {
  19. TreeNode p = head, q = tail;
  20. while (p != q) {
  21. int sum = p.val + q.val;
  22. //seenSum.add(sum);
  23. if (sum > value) {
  24. q = q.pre;
  25. } else if (sum < value) {
  26. p = p.next;
  27. } else {
  28. return true;
  29. }
  30. }
  31. }
  32. }
  33. return false;
  34. }
  35.  
  36. private void insertIntoTree(int val) {
  37. TreeNode p = root;
  38. TreeNode pre = null;
  39. TreeNode next = null;
  40. while (true) {
  41. //seenSum.add(val + p.val);
  42. if (val > p.val) {
  43. pre = p;
  44. if (p.right != null) {
  45. p = p.right;
  46. } else {
  47. p.right = new TreeNode(val);
  48. insertInToChain(p.right, pre, next);
  49. break;
  50. }
  51. } else {
  52. next = p;
  53. if (p.left != null) {
  54. p = p.left;
  55. } else {
  56. p.left = new TreeNode(val);
  57. insertInToChain(p.left, pre, next);
  58. break;
  59. }
  60. }
  61. }
  62. }
  63.  
  64. private void insertInToChain(TreeNode n, TreeNode pre, TreeNode next) {
  65. if (pre != null) {
  66. pre.next = n;
  67. } else {
  68. head = n;
  69. }
  70. if (next != null) {
  71. next.pre = n;
  72. } else {
  73. tail = n;
  74. }
  75. n.pre = pre;
  76. n.next = next;
  77. }
  78.  
  79. private static class TreeNode {
  80. int val;
  81. TreeNode right;
  82. TreeNode left;
  83. TreeNode pre;
  84. TreeNode next;
  85. TreeNode(int val) {
  86. this.val = val;
  87. }
  88. }
  89. }
注意到撸主注释的部分,有一个优化。就是在插入和搜索过程中,沿途找到的sum我们缓存起来,下次说不定可以用。Find的之前可以先在seenset里面看看。
Read full article from leetcode 170: Two Sum III - Data structure design - 西施豆腐渣 - 博客频道 - CSDN.NET

Labels

LeetCode (1432) GeeksforGeeks (1122) LeetCode - Review (1067) Review (882) Algorithm (668) to-do (609) Classic Algorithm (270) Google Interview (237) Classic Interview (222) Dynamic Programming (220) DP (186) Bit Algorithms (145) POJ (141) Math (137) Tree (132) LeetCode - Phone (129) EPI (122) Cracking Coding Interview (119) DFS (115) Difficult Algorithm (115) Lintcode (115) Different Solutions (110) Smart Algorithm (104) Binary Search (96) BFS (91) HackerRank (90) Binary Tree (86) Hard (79) Two Pointers (78) Stack (76) Company-Facebook (75) BST (72) Graph Algorithm (72) Time Complexity (69) Greedy Algorithm (68) Interval (63) Company - Google (62) Geometry Algorithm (61) Interview Corner (61) LeetCode - Extended (61) Union-Find (60) Trie (58) Advanced Data Structure (56) List (56) Priority Queue (53) Codility (52) ComProGuide (50) LeetCode Hard (50) Matrix (50) Bisection (48) Segment Tree (48) Sliding Window (48) USACO (46) Space Optimization (45) Company-Airbnb (41) Greedy (41) Mathematical Algorithm (41) Tree - Post-Order (41) ACM-ICPC (40) Algorithm Interview (40) Data Structure Design (40) Graph (40) Backtracking (39) Data Structure (39) Jobdu (39) Random (39) Codeforces (38) Knapsack (38) LeetCode - DP (38) Recursive Algorithm (38) String Algorithm (38) TopCoder (38) Sort (37) Introduction to Algorithms (36) Pre-Sort (36) Beauty of Programming (35) Must Known (34) Binary Search Tree (33) Follow Up (33) prismoskills (33) Palindrome (32) Permutation (31) Array (30) Google Code Jam (30) HDU (30) Array O(N) (29) Logic Thinking (29) Monotonic Stack (29) Puzzles (29) Code - Detail (27) Company-Zenefits (27) Microsoft 100 - July (27) Queue (27) Binary Indexed Trees (26) TreeMap (26) to-do-must (26) 1point3acres (25) GeeksQuiz (25) Merge Sort (25) Reverse Thinking (25) hihocoder (25) Company - LinkedIn (24) Hash (24) High Frequency (24) Summary (24) Divide and Conquer (23) Proof (23) Game Theory (22) Topological Sort (22) Lintcode - Review (21) Tree - Modification (21) Algorithm Game (20) CareerCup (20) Company - Twitter (20) DFS + Review (20) DP - Relation (20) Brain Teaser (19) DP - Tree (19) Left and Right Array (19) O(N) (19) Sweep Line (19) UVA (19) DP - Bit Masking (18) LeetCode - Thinking (18) KMP (17) LeetCode - TODO (17) Probabilities (17) Simulation (17) String Search (17) Codercareer (16) Company-Uber (16) Iterator (16) Number (16) O(1) Space (16) Shortest Path (16) itint5 (16) DFS+Cache (15) Dijkstra (15) Euclidean GCD (15) Heap (15) LeetCode - Hard (15) Majority (15) Number Theory (15) Rolling Hash (15) Tree Traversal (15) Brute Force (14) Bucket Sort (14) DP - Knapsack (14) DP - Probability (14) Difficult (14) Fast Power Algorithm (14) Pattern (14) Prefix Sum (14) TreeSet (14) Algorithm Videos (13) Amazon Interview (13) Basic Algorithm (13) Codechef (13) Combination (13) Computational Geometry (13) DP - Digit (13) LCA (13) LeetCode - DFS (13) Linked List (13) Long Increasing Sequence(LIS) (13) Math-Divisible (13) Reservoir Sampling (13) mitbbs (13) Algorithm - How To (12) Company - Microsoft (12) DP - Interval (12) DP - Multiple Relation (12) DP - Relation Optimization (12) LeetCode - Classic (12) Level Order Traversal (12) Prime (12) Pruning (12) Reconstruct Tree (12) Thinking (12) X Sum (12) AOJ (11) Bit Mask (11) Company-Snapchat (11) DP - Space Optimization (11) Dequeue (11) Graph DFS (11) MinMax (11) Miscs (11) Princeton (11) Quick Sort (11) Stack - Tree (11) 尺取法 (11) 挑战程序设计竞赛 (11) Coin Change (10) DFS+Backtracking (10) Facebook Hacker Cup (10) Fast Slow Pointers (10) HackerRank Easy (10) Interval Tree (10) Limited Range (10) Matrix - Traverse (10) Monotone Queue (10) SPOJ (10) Starting Point (10) States (10) Stock (10) Theory (10) Tutorialhorizon (10) Kadane - Extended (9) Mathblog (9) Max-Min Flow (9) Maze (9) Median (9) O(32N) (9) Quick Select (9) Stack Overflow (9) System Design (9) Tree - Conversion (9) Use XOR (9) Book Notes (8) Company-Amazon (8) DFS+BFS (8) DP - States (8) Expression (8) Longest Common Subsequence(LCS) (8) One Pass (8) Quadtrees (8) Traversal Once (8) Trie - Suffix (8) 穷竭搜索 (8) Algorithm Problem List (7) All Sub (7) Catalan Number (7) Cycle (7) DP - Cases (7) Facebook Interview (7) Fibonacci Numbers (7) Flood fill (7) Game Nim (7) Graph BFS (7) HackerRank Difficult (7) Hackerearth (7) Inversion (7) Kadane’s Algorithm (7) Manacher (7) Morris Traversal (7) Multiple Data Structures (7) Normalized Key (7) O(XN) (7) Radix Sort (7) Recursion (7) Sampling (7) Suffix Array (7) Tech-Queries (7) Tree - Serialization (7) Tree DP (7) Trie - Bit (7) 蓝桥杯 (7) Algorithm - Brain Teaser (6) BFS - Priority Queue (6) BFS - Unusual (6) Classic Data Structure Impl (6) DP - 2D (6) DP - Monotone Queue (6) DP - Unusual (6) DP-Space Optimization (6) Dutch Flag (6) How To (6) Interviewstreet (6) Knapsack - MultiplePack (6) Local MinMax (6) MST (6) Minimum Spanning Tree (6) Number - Reach (6) Parentheses (6) Pre-Sum (6) Probability (6) Programming Pearls (6) Rabin-Karp (6) Reverse (6) Scan from right (6) Schedule (6) Stream (6) Subset Sum (6) TSP (6) Xpost (6) n00tc0d3r (6) reddit (6) AI (5) Abbreviation (5) Anagram (5) Art Of Programming-July (5) Assumption (5) Bellman Ford (5) Big Data (5) Code - Solid (5) Code Kata (5) Codility-lessons (5) Coding (5) Company - WMware (5) Convex Hull (5) Crazyforcode (5) DFS - Multiple (5) DFS+DP (5) DP - Multi-Dimension (5) DP-Multiple Relation (5) Eulerian Cycle (5) Graph - Unusual (5) Graph Cycle (5) Hash Strategy (5) Immutability (5) Java (5) LogN (5) Manhattan Distance (5) Matrix Chain Multiplication (5) N Queens (5) Pre-Sort: Index (5) Quick Partition (5) Quora (5) Randomized Algorithms (5) Resources (5) Robot (5) SPFA(Shortest Path Faster Algorithm) (5) Shuffle (5) Sieve of Eratosthenes (5) Strongly Connected Components (5) Subarray Sum (5) Sudoku (5) Suffix Tree (5) Swap (5) Threaded (5) Tree - Creation (5) Warshall Floyd (5) Word Search (5) jiuzhang (5)

Popular Posts