LeetCode 658 - Find K Closest Elements


https://leetcode.com/problems/find-k-closest-elements
Given a sorted array, two integers k and x, find the k closest elements to x in the array. The result should also be sorted in ascending order. If there is a tie, the smaller elements are always preferred.
Example 1:
Input: [1,2,3,4,5], k=4, x=3
Output: [1,2,3,4]
Example 2:
Input: [1,2,3,4,5], k=4, x=-1
Output: [1,2,3,4]
Note:
  1. The value k is positive and will always be smaller than the length of the sorted array.
  2. Length of the given array is positive and will not exceed 104
  3. Absolute value of elements in the array and x will not exceed 104

https://leetcode.com/articles/find-k-closest-elements/
Approach #2 Using Binary Search and Two Pointers
The original array has been sorted so we can take this advantage by the following steps. 1. If the target xis less or equal than the first element in the sorted array, the first k elements are the result. 2. Similarly, if the target x is more or equal than the last element in the sorted array, the last k elements are the result. 3. Otherwise, we can use binary search to find the index of the element, which is equal (when this list has x) or a little bit larger than x (when this list does not have it). Then set low to its left k-1 position, and highto the right k-1 position of this index as a start. The desired k numbers must in this rang [index-k-1, index+k-1]. So we can shrink this range to get the result using the following rules. * If low reaches the lowest index 0 or the low element is closer to x than the high element, decrease the high index. * If high reaches to the highest index arr.size()-1 or it is nearer to x than the low element, increase the low index. * The looping ends when there are exactly k elements in [low, high], the subList of which is the result.
  • Time complexity : O(log(n)+k)O(log(n)) is for the time of binary search, while O(k) is for shrinking the index range to k elements.
  • Space complexity : O(k). It is to generate the required sublist.
  public List<Integer> findClosestElements(List<Integer> arr, int k, int x) {
    int n = arr.size();
    if (x <= arr.get(0)) {
      return arr.subList(0, k);
    } else if (arr.get(n - 1) <= x) {
      return arr.subList(n - k, n);
    } else {
      int index = Collections.binarySearch(arr, x);
      if (index < 0)
        index = -index - 1;
      int low = Math.max(0, index - k - 1), high = Math.min(arr.size() - 1, index + k - 1);

      while (high - low > k - 1) {
        if (low < 0 || (x - arr.get(low)) <= (arr.get(high) - x))
          high--;
        else if (high > arr.size() - 1 || (x - arr.get(low)) > (arr.get(high) - x))
          low++;
        else
          System.out.println("unhandled case: " + low + " " + high);
      }
      return arr.subList(low, high + 1);
    }

  }
https://discuss.leetcode.com/topic/99194/binary-search-and-two-pointers-18-ms
Noticing the array is sorted, so we can using binary search to get a rough area of target numbers, and then expand it to the left k-1 more and right k-1 more elements, then searching from the left to right. If the left element is more close or equal to the target number x than the right element, then move the right index to the left one step. Otherwise, move the left index to right one step. Once, the element between the left and right is k, then return the result.
 public List<Integer> findClosestElements(List<Integer> arr, int k, int x) {
  int n = arr.size();
  if (x <= arr.get(0)) {
   return arr.subList(0, k);
  } else if (arr.get(n - 1) <= x) {
   return arr.subList(n - k, n);
  } else {
   int index = Collections.binarySearch(arr, x);
   if (index < 0)
    index = -index - 1;
   int low = Math.max(0, index - k - 1), high = Math.min(arr.size() - 1, index + k - 1);

   while (high - low > k - 1) {
    if (low < 0 || (x - arr.get(low)) <= (arr.get(high) - x))
     high--;
    else if (high > arr.size() - 1 || (x - arr.get(low)) > (arr.get(high) - x))
     low++;
    else
     System.out.println("unhandled case: " + low + " " + high);
   }
   return arr.subList(low, high + 1);
  }
 }
X. https://leetcode.com/problems/find-k-closest-elements/discuss/106419/O(log-n)-Java-1-line-O(log(n)-%2B-k)-Ruby


I binary-search for where the resulting elements start in the array. It's the first index i so that arr[i] is better than arr[i+k] (with "better" meaning closer to or equally close to x). Then I just return the k elements starting there.

The binary search costs O(log n) (actually also just O(log (n-k)) and the subList call probably only takes O(1). As @sagimann pointed outsubList returns a view, not a separate copy. So it should only take O(1). Can be seen for example in ArrayList's subList and the SubList constructor it calls. I also checked LinkedList, it gets its subList method inherited from AbstractList, where it also takes only O(1). And AbstractList is a basis for most lists.
public List<Integer> findClosestElements(List<Integer> arr, int k, int x) {
    int lo = 0, hi = arr.size() - k;
    while (lo < hi) {
        int mid = (lo + hi) / 2;
        if (x - arr.get(mid) > arr.get(mid+k) - x)
            lo = mid + 1;
        else
            hi = mid;
    }
    return arr.subList(lo, lo + k);
}
https://leetcode.com/problems/find-k-closest-elements/discuss/106426/JavaC%2B%2BPython-Binary-Research-O(log(N-K))
Assume we are taking A[i] ~ A[i + k -1].
We can binary research i
We compare the distance between x - A[mid] and A[mid - k] - x


If x - A[mid] > A[mid + k] - x,
it means A[mid + 1] ~ A[mid + k] is better than A[mid] ~ A[mid + k - 1],
and we have mid smaller than the right i.
So assign left = mid + 1.

https://discuss.leetcode.com/topic/99178/java-o-logn-klogk-solution-with-priorityqueue-and-binary-search

O(nlog(n)) Time Solution:
public List<Integer> findClosestElements(List<Integer> arr, int k, int x) {
     Collections.sort(arr, (a,b) -> a == b ? a - b : Math.abs(a-x) - Math.abs(b-x));
     arr = arr.subList(0, k);
     Collections.sort(arr);
     return arr;
}

O(n) Time Solution:
public List<Integer> findClosestElements(List<Integer> arr, int k, int x) {
    List<Integer> less = new ArrayList<>(), greater = new ArrayList<>(),
                  lessResult = new LinkedList<>(), greaterResult = new LinkedList<>();
 
    for (Integer i : arr) {
        if (i <= x) less.add(i);
        else greater.add(i);
    }
    
    Collections.reverse(less);
    int  i = 0, j = 0, n = less.size(), m = greater.size();
    for (int size=0;size<k;size++) {
        if (i < n && j < m) {
            if (Math.abs(less.get(i) - x) <= Math.abs(greater.get(j) - x)) lessResult.add(less.get(i++));
            else greaterResult.add(greater.get(j++));
        }
        else if (i < n) lessResult.add(less.get(i++));
        else greaterResult.add(greater.get(j++));
    }

    Collections.reverse(lessResult);
    lessResult.addAll(greaterResult);
    return lessResult;
}

1. 变种:找离某⼀一点最近的k个点
2. followup是⽤用pq的time complexity是nlogn,能否improve
https://github.com/mintycc/OnlineJudge-Solutions/blob/master/untag/Find%20Kth%20Closest%20Points/FindKthClosestPoints.java
    public class Point {
        int x, y, dist;
        Point(int x, int y) {
            this.x = x;
            this.y = y;
            dist = x * x + y * y;
        }
    }

    public List<Point> findKthPQ(List<Point> points, int k) {
        PriorityQueue<Point> pq = new PriorityQueue<>(new Comparator<Point>() {
            public int compare(Point a, Point b) {
                return b.dist - a.dist;
            }
        });
        for (Point point : points) {
            if (pq.size() < k) pq.add(point);
            else if (point.dist < pq.peek().dist) {
                pq.poll();
                pq.add(point);
            }
        }
        List<Point> ans = new ArrayList<>();
        while (!pq.isEmpty()) ans.add(pq.poll());
        return ans;
    }

    public List<Point> findKthQS(List<Point> points, int k) {
        quickSelect(points, 0, points.size() - 1, k - 1);
        List<Point> ans = new ArrayList<>();
        for (int i = 0; i < k; i ++)
            ans.add(points.get(i));
        return ans;
    }

    private void quickSelect(List<Point> points, int l, int r, int k) {
        if (l == r) return;
        Point pivot = points.get(r);
        int i = l, j = r - 1;
        do {
            while (i < r && points.get(i).dist < pivot.dist) i ++;
            while (l < j && points.get(j).dist > pivot.dist) j --;
            if (i < j) swap(points, i ++, j --);
        } while (i < j);
        swap(points, i, r);
        if (i == k) return;
        if (k < i) quickSelect(points, l, i - 1, k);
        else quickSelect(points, i + 1, r, k);
    }

    private void swap(List<Point> points, int a, int b) {
        Point tmp = points.get(a);
        points.set(a, points.get(b));
        points.set(b, tmp);
    }





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