Lintcode 139 - Subarray Sum Closest


Two elements whose sum is closest to zero
[Lintcode] Subarray Sum Closest
Given an integer array, find a subarray with sum closest to zero. Return the indexes of the first number and last number.

Example
Given [-3, 1, 1, -3, 5], return [0, 2][1, 3][1, 1][2, 2] or [0, 4].

Challenge
O(nlogn) time
http://www.jiuzhang.com/solutions/subarray-sum-closest/
问:为什么需要一个 (0,0) 的初始 Pair?
答:
我们首先需要回顾一下,在 subarray 这节课里,我们讲过一个重要的知识点,叫做 Prefix Sum
比如对于数组 [1,2,3,4],他的 Prefix Sum 是 [1,3,6,10]
分别表示 前1个数之和,前2个数之和,前3个数之和,前4个数之和
这个时候如果你想要知道 子数组 从下标  1 到下标 2 的这一段的和(2+3),就用前 3个数之和 减去 前1个数之和 = PrefixSum[2] - PrefixSum[0] = 6 - 1 = 5
你可以看到这里的 前 x 个数,和具体对应的下标之间,存在 +-1 的问题
第 x 个数的下标是 x - 1,反之 下标 x 是第 x + 1 个数
那么问题来了,如果要计算 下标从 0~2 这一段呢?也就是第1个数到第3个数,因为那样会访问到 PrefixSum[-1]
所以我们把 PrefixSum 整体往后面移动一位,把第0位空出来表示前0个数之和,也就是0. => [0,1,3,6,10]
那么此时就用 PrefixSum[3] - PrefixSum[0] ,这样计算就更方便了。
此时,PrefixSum[i] 代表 前i个数之和,也就是 下标区间在 0 ~ i-1 这一段的和

那么回过头来看看,为什么我们需要一个 (0,0) 的 pair 呢?
因为 这个 0,0 代表的就是前0个数之和为0
一个 n 个数的数组, 变成了 prefix Sum 数组之后,会多一个数出来
https://xuezhashuati.blogspot.com/2017/04/lintcode-139-subarray-sum-closest.html
看到subarray又想到prefixSum。
我们算出所有的prefixSum,排个序。维护一个最小值closest,遍历一下排好序的sortedSum数组,相邻的两个看一下差如果小于closest,就更新答案。
class Pair {
    int sum;
    int index;
    public Pair (int sum, int index) {
        this.sum = sum;
        this.index = index;
    }
}
    public int[] subarraySumClosest(int[] nums) {        
        int[] res = new int[2];
        if (nums == null || nums.length == 0) {//
            return res;
        }
        
        if (nums.length == 1) {//\\
            res[0] = 0;
            res[1] = 0;
            return res;
        }
        
        
        Pair[] prefixSum = new Pair[nums.length + 1];
        prefixSum[0] = new Pair(0, 0);//
        for (int i = 1; i <= nums.length; i++) {
            prefixSum[i] = new Pair(prefixSum[i - 1].sum + nums[i - 1], i);
        }
        
        Pair[] sortedSum = prefixSum;
        Arrays.sort(sortedSum, new Comparator<Pair>() { //key here
            public int compare(Pair x, Pair y) {
                return x.sum - y.sum;
            }
        });
        
        int closest = Integer.MAX_VALUE;
        for (int i = 1; i < sortedSum.length; i++) {
            if (sortedSum[i].sum - sortedSum[i - 1].sum < closest) { // may overflow
                closest = sortedSum[i].sum - sortedSum[i - 1].sum;
                res[0] = sortedSum[i].index - 1;
                res[1] = sortedSum[i - 1].index - 1;
            }
        }
        
        Arrays.sort(res);
        res[0]++;
        return res;
    }
    public int[] subarraySumClosest(int[] nums) {
        int[] res = new int[2];
        if (nums == null || nums.length == 0) {
            return res;
        } 
        
        int len = nums.length;
        if(len == 1) {
            res[0] = res[1] = 0;
            return res;
        }
        Pair[] sums = new Pair[len+1];
        int prev = 0;
        sums[0] = new Pair(0, 0);
        for (int i = 1; i <= len; i++) {
            sums[i] = new Pair(prev + nums[i-1], i);
            prev = sums[i].sum;
        }
        Arrays.sort(sums, new Comparator<Pair>() {
           public int compare(Pair a, Pair b) {
               return a.sum - b.sum;
           } 
        });
        int ans = Integer.MAX_VALUE;
        for (int i = 1; i <= len; i++) {
            
            if (ans > sums[i].sum - sums[i-1].sum) {
                ans = sums[i].sum - sums[i-1].sum;
                int[] temp = new int[]{sums[i].index - 1, sums[i - 1].index - 1};
                Arrays.sort(temp);
                res[0] = temp[0] + 1;
                res[1] = temp[1];
            }
        }
        
        return res;
    }

O(nlogn) time: pre-sum with pre-sum value and index, sort presum;
s[i] = nums[0]+....nums[i], also record the index i into s[i]. Sort array s, and the minimum difference between two consecutive element, is the the subarray.
28     public ArrayList<Integer> subarraySumClosest(int[] nums) {
29         ArrayList<Integer> res = new ArrayList<Integer>();
30         if (nums.length==0) return res;
31 
32         Element[] sums = new Element[nums.length+1];
33         sums[0] = new Element(0,-1);
34         int sum = 0;
35         for (int i=0;i<nums.length;i++){
36             sum += nums[i];
37             sums[i+1] = new Element(sum,i);
38         }
39 
40         Arrays.sort(sums);
41         int min = Math.abs(sums[0].getValue() - sums[1].getValue());
42         int start =  Math.min(sums[0].getIndex(), sums[1].getIndex())+1;
43         int end = Math.max(sums[0].getIndex(), sums[1].getIndex());
44         for (int i=1;i<nums.length;i++){// if i start with 1, then should compare i with i-1; so we don't handle i=0 specially.
45             int diff = Math.abs(sums[i].getValue() - sums[i+1].getValue());
46             if (diff<min){
47                 min = diff;
48                 start = Math.min(sums[i].getIndex(), sums[i+1].getIndex())+1;
49                 end  = Math.max(sums[i].getIndex(), sums[i+1].getIndex());
50             }
51         }
52         res.add(start);
54         res.add(end);
55         return res;
56     }
http://algorithm.yuanbin.me/integer_array/subarray_sum_closest.html
为避免对单个子串和是否为最小情形的单独考虑,我们可以采取类似链表 dummy 节点的方法规避,简化代码实现。故初始化sum_index时需要num_size + 1个。这里为避免 vector 反复扩充空间降低运行效率,使用resize一步到位。sum_index即最后结果中left_index和right_index等边界可以结合简单例子分析确定。
    vector<int> subarraySumClosest(vector<int> nums){
        vector<int> result;
        if (nums.empty()) {
            return result;
        }

        const int num_size = nums.size();
        vector<pair<int, int> > sum_index(num_size + 1);

        for (int i = 0; i < num_size; ++i) {
            sum_index[i + 1].first = sum_index[i].first + nums[i];
            sum_index[i + 1].second = i + 1;
        }

        sort(sum_index.begin(), sum_index.end());

        int min_diff = INT_MAX;
        int closest_index = 1; // better, we compute start, end at last step.
        for (int i = 1; i < num_size + 1; ++i) {
            int sum_diff = abs(sum_index[i].first - sum_index[i - 1].first);
            if (min_diff > sum_diff) {
                min_diff = sum_diff;
                closest_index = i;
            }
        }
        int left_index = min(sum_index[closest_index - 1].second,\
                             sum_index[closest_index].second);
        int right_index = -1 + max(sum_index[closest_index - 1].second,\
                                   sum_index[closest_index].second);
        result.push_back(left_index);
        result.push_back(right_index);
        return result;
    }
https://github.com/kamyu104/LintCode/blob/master/C++/subarray-sum-closest.cpp
Using Treemap: to find close value
这个解法比较复杂,用到了treemap。 是通用与找closest to target k 的解法。简单解法参考subarray sum。排序即可。
https://codesolutiony.wordpress.com/2015/04/24/lintcode%EF%BC%9Asubarray-sum-closest-subarray-sum-closest-to-k/
    public ArrayList<Integer> subarraySumClosest(int[] nums) {
        ArrayList<Integer> res = new ArrayList<Integer>();
        if (nums == null || nums.length == 0) {
            return res;
        }
        TreeMap<Long, Integer> map = new TreeMap<Long, Integer>();
        long sum = 0;
        long minDiff = (long)Integer.MAX_VALUE + 1;
        res.add(0);
        res.add(0);
        for (int i = 0; i < nums.length; i++) {
            sum += nums[i];
            Entry floorEntry = map.floorEntry(sum);
            Entry ceilingEntry = map.ceilingEntry(sum);
            int curDiff = 0;
            if (floorEntry != null || ceilingEntry != null) {
                if (floorEntry == null || (ceilingEntry != null && Math.abs((long)floorEntry.getKey() - sum) > Math.abs((long)ceilingEntry.getKey() - sum))) {
                    if (Math.abs((long)ceilingEntry.getKey() - sum) < minDiff) {
                        res.set(0, (int)ceilingEntry.getValue() + 1);
                        res.set(1, i);
                    }
                } else {
                    if (Math.abs((long)floorEntry.getKey() - sum) < minDiff) {
                        res.set(0, (int)floorEntry.getValue() + 1);
                        res.set(1, i);
                        minDiff = Math.abs((long)floorEntry.getKey() - sum);
                    }
                }
            }
            map.put(sum, i);
        }          
        return res;
    }

https://shawnlincoding.wordpress.com/2015/08/31/481/
    public ArrayList<Integer> subarraySumClosest(int[] nums) {
        if (nums == null || nums.length == 0) {
            return null;
        }
        TreeMap<Integer, Integer> bst = new TreeMap<Integer, Integer>();
        bst.put(0, -1);
        int prefix = 0;
        int minDiff = Integer.MAX_VALUE;
        ArrayList<Integer> res = new ArrayList<Integer>();
        int left = 0, right = 0;
        for (int i = 0; i < nums.length; i++) {
            prefix += nums[i];
            Map.Entry<Integer, Integer> pred = bst.floorEntry(prefix);
            if (pred != null) {
                int diff = Math.abs(pred.getKey() - prefix);
                if (minDiff > diff) {
                    minDiff = diff;
                    left = pred.getValue() + 1;
                    right = i;
                }
            }
            Map.Entry<Integer, Integer> succ = bst.ceilingEntry(prefix);
            if (succ != null) {
                int diff = Math.abs(succ.getKey() - prefix);
                if (minDiff > diff) {
                    minDiff = diff;
                    left = succ.getValue() + 1;
                    right = i;
                }
            }
            bst.put(prefix, i);
        }
        res.add(left);
        res.add(right);
        return res;
    }
https://discuss.leetcode.com/topic/63618/how-to-find-the-subarray-that-has-sum-closest-to-zero-or-a-certain-value-t-in-o-nlogn

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