Showing posts with label Quick Select. Show all posts
Showing posts with label Quick Select. Show all posts

LeetCode 973 - K Closest Points to Origin


https://leetcode.com/problems/k-closest-points-to-origin/
We have a list of points on the plane.  Find the K closest points to the origin (0, 0).
(Here, the distance between two points on a plane is the Euclidean distance.)
You may return the answer in any order.  The answer is guaranteed to be unique (except for the order that it is in.)

Example 1:
Input: points = [[1,3],[-2,2]], K = 1
Output: [[-2,2]]
Explanation: 
The distance between (1, 3) and the origin is sqrt(10).
The distance between (-2, 2) and the origin is sqrt(8).
Since sqrt(8) < sqrt(10), (-2, 2) is closer to the origin.
We only want the closest K = 1 points from the origin, so the answer is just [[-2,2]].
Example 2:
Input: points = [[3,3],[5,-1],[-2,4]], K = 2
Output: [[3,3],[-2,4]]
(The answer [[-2,4],[3,3]] would also be accepted.)

Note:
  1. 1 <= K <= points.length <= 10000
  2. -10000 < points[i][0] < 10000
  3. -10000 < points[i][1] < 10000
https://leetcode.com/problems/k-closest-points-to-origin/discuss/217969/Java-8-liner-using-PriorityQueue-O(nlogK).


  1. Put the points into a PriorityQueue, and the order is by their distance to origin descendingly;
  2. Whenever the size reach K + 1, poll the farthest point out.
    public int[][] kClosest(int[][] points, int K) {
        PriorityQueue<int[]> pq = new PriorityQueue<>(Comparator.comparing(a -> -a[0] * a[0] - a[1] * a[1]));
        for (int[] p : points) { 
            pq.offer(p); 
            if (pq.size() > K) { pq.poll(); } // poll out the farthest among the K + 1 points.
        }
        int[][] ans = new int[K][2];
        while (K-- > 0) { ans[K] = pq.poll(); }
        return ans;
    }
X. Quick select
The last solution is based on quick sort, we can also call it quick select. In the quick sort, we will always choose a pivot to compare with other elements. After one iteration, we will get an array that all elements smaller than the pivot are on the left side of the pivot and all elements greater than the pivot are on the right side of the pviot (assuming we sort the array in ascending order). So, inspired from this, each iteration, we choose a pivot and then find the position p the pivot should be. Then we compare p with the K, if the p is smaller than the K, meaning the all element on the left of the pivot are all proper candidates but it is not adequate, we have to do the same thing on right side, and vice versa. If the p is exactly equal to the K, meaning that we've found the K-th position. Therefore, we just return the first K elements, since they are not greater than the pivot.
Theoretically, the average time complexity is O(N) , but just like quick sort, in the worst case, this solution would be degenerated to O(N^2), and pratically, the real time it takes on leetcode is 15ms.
The advantage of this solution is it is very efficient.
The disadvatage of this solution are it is neither an online solution nor a stable one. And the first K elements are not sorted in ascending order.
The short code shows as follows:
public int[][] kClosest(int[][] points, int K) {
    int len =  points.length, l = 0, r = len - 1;
    while (l <= r) {
        int mid = helper(points, l, r);
        if (mid == K) break;
        if (mid < K) {
            l = mid + 1;
        } else {
            r = mid - 1;
        }
    }
    return Arrays.copyOfRange(points, 0, K);
}

private int helper(int[][] A, int l, int r) {
    int[] pivot = A[l];
    while (l < r) {
        while (l < r && compare(A[r], pivot) >= 0) r--;
        A[l] = A[r];
        while (l < r && compare(A[l], pivot) <= 0) l++;
        A[r] = A[l];
    }
    A[l] = pivot;
    return l;
}

private int compare(int[] p1, int[] p2) {
    return p1[0] * p1[0] + p1[1] * p1[1] - p2[0] * p2[0] - p2[1] * p2[1];
}
https://leetcode.com/articles/k-closest-points-to-origin/
Let's do the work(i, j, K) of partially sorting the subarray (points[i], points[i+1], ..., points[j]) so that the smallest K elements of this subarray occur in the first K positions (i, i+1, ..., i+K-1).
First, we quickselect by a random pivot element from the subarray. To do this in place, we have two pointers i and j, and move these pointers to the elements that are in the wrong bucket -- then, we swap these elements.
After, we have two buckets [oi, i] and [i+1, oj], where (oi, oj) are the original (i, j) values when calling work(i, j, K). Say the first bucket has 10 items and the second bucket has 15 items. If we were trying to partially sort say, K = 5 items, then we only need to partially sort the first bucket: work(oi, i, 5). Otherwise, if we were trying to partially sort say, K = 17 items, then the first 10 items are already partially sorted, and we only need to partially sort the next 7 items: work(i+1, oj, 7).

  int[][] points;

  public int[][] kClosest(int[][] points, int K) {
    this.points = points;
    work(0, points.length - 1, K);
    return Arrays.copyOfRange(points, 0, K);
  }

  public void work(int i, int j, int K) {
    if (i >= j)
      return;
    int oi = i, oj = j;
    int pivot = dist(ThreadLocalRandom.current().nextInt(i, j));

    while (i < j) {
      while (i < j && dist(i) < pivot)
        i++;
      while (i < j && dist(j) > pivot)
        j--;
      swap(i, j);
    }

    if (K <= i - oi + 1)
      work(oi, i, K);
    else
      work(i + 1, oj, K - (i - oi + 1));
  }

  public int dist(int i) {
    return points[i][0] * points[i][0] + points[i][1] * points[i][1];
  }

  public void swap(int i, int j) {
    int t0 = points[i][0], t1 = points[i][1];
    points[i][0] = points[j][0];
    points[i][1] = points[j][1];
    points[j][0] = t0;
    points[j][1] = t1;

  }

X. Sort the points by distance, then take the closest K points.



LeetCode - 462 Minimum Moves to Equal Array Elements II


LeetCode 453 - Minimum Moves to Equal Array Elements
http://bookshadow.com/weblog/2016/11/20/leetcode-minimum-moves-to-equal-array-elements-ii/
Given a non-empty integer array, find the minimum number of moves required to make all array elements equal, where a move is incrementing a selected element by 1 or decrementing a selected element by 1.
You may assume the array's length is at most 10,000.
Example:
Input:
[1,2,3]

Output:
2

Explanation:
Only two moves are needed (remember each move increments or decrements one element):

[1,2,3]  =>  [2,2,3]  =>  [2,2,2]
https://discuss.leetcode.com/topic/68736/java-just-like-meeting-point-problem
Need not to sort the entire array. Linear time QuickSelect is preferred here to compute median and solve this problem in O(n).
Suppose you have two endpoints A and B, when you want to find a point C that has minimum sum of distance between AC and BC, the point C will always between A and B. Draw a graph and you will understand it. Lets keep moving forward. After we locating the point C between A and B, we can define that
dis(AC) = c - a; dis(CB) = b - c;
sum = dis(AC) + dis(CB) = b - a.
b - a will be a constant value, given specific b and a. Thus there will be no difference between points among A and B.
In this problem, we set two boundaries, saying i and j, and we move the i and j to do the computation.
you can think the number in the array is the position in 1d array. so, we need to find a position that all positions can reach and the sum is minimum.
https://discuss.leetcode.com/topic/68762/java-solution-with-thinking-process/5
    public int minMoves2(int[] nums) {
        Arrays.sort(nums);
        int i = 0, j = nums.length-1;
        int count = 0;
        while(i < j){
            count += nums[j]-nums[i];
            i++;
            j--;
        }
        return count;
    }
    public int minMoves2(int[] nums) {
        Arrays.sort(nums);
        int res = 0, mid = nums.length/2;
        for(int i = 0; i < nums.length; i++){
            res += i > mid ? nums[i] - nums[mid] : nums[mid] - nums[i];
        }
        return res;
    }

求数组各元素与中位数差的绝对值之和
def minMoves2(self, nums): """ :type nums: List[int] :rtype: int """ nums.sort() median = nums[len(nums) / 2] return sum(abs(num - median) for num in nums)

参考《编程之美》 小飞的电梯调度算法 解析
def minMoves2(self, nums): """ :type nums: List[int] :rtype: int """ cnt = collections.Counter(nums) last, size = min(nums), len(nums) ans = mov = sum(nums) - last * size lo, hi = 0, size for k in sorted(cnt): mov += (lo - hi) * (k - last) hi -= cnt[k] lo += cnt[k] ans = min(ans, mov) last = k return ans

X. Quick Select
https://discuss.leetcode.com/topic/69236/o-n-solution-with-detailed-explanation
// Imagine the nums are sorted, and the final value is k, we start find k from the first element.
// If we increase k, the elements <= k will need move one step more, and the elements > k will need to move one step less.
// If there are more elements > k than elements <= k, we should increase k to minimize the moves.
// So we just increase k, until k reach the median of of the nums array. By then, the number of elements <= k equals to that of elements > k.
// (There is a slight different when the number of array is odd, but it's similar).
// If we keep increasing k after k reach the median of the array, more numbers >k than <= k, and more moves needed, so we should stop.
//
// The sort is not needed since we find the k is the median of the array, there is an average O(n) algorithm to find such k.

https://discuss.leetcode.com/topic/68758/java-o-n-time-using-quickselect
This solution relies on the fact that if we increment/decrement each element to the median of all the elements, the optimal number of moves is necessary. The median of all elements can be found in expected O(n) time using QuickSelect (or deterministic O(n) time using Median of Medians).
public int minMoves2(int[] nums) {
    int sum = 0;
    int median = findMedian(nums);
    for (int i=0;i<nums.length;i++) {
        sum += Math.abs(nums[i] - median);
    }
    return sum;
}

public int findMedian(int[] nums) {
    return getKth(nums.length/2+1, nums, 0, nums.length - 1);
}

public int getKth(int k, int[] nums, int start, int end) {
    int pivot = nums[end];
    int left = start;
    int right = end;

    while (true) {
        while (nums[left] < pivot && left < right) left++;
        while (nums[right] >= pivot && right > left) right--;
        if (left == right) break;
        swap(nums, left, right);
    }

    swap(nums, left, end);
    if (k == left + 1)  return pivot;
    else if (k < left + 1) return getKth(k, nums, start, left - 1);
    else return getKth(k, nums, left + 1, end);
}

public void swap(int[] nums, int n1, int n2) {
 int tmp = nums[n1];
 nums[n1] = nums[n2];
 nums[n2] = tmp;
}


Google – Minimum Word Set with Frequency Sum Greater than Target


Google – Minimum Word Set with Frequency Sum Greater than Target
给一篇文章,里面有很多单词,整篇文章可以全部装入内存,再给一个target number, 要求返回一个最小的set,使得set里那些单词的出现频率总和大于等于target number
[Solution]
#1 sort
#2 quick select
这道题quick select的思路的确很巧。但是仔细想一下这道题除了sort之外一时半会儿也想不到其他方法。而凡是能用sort做的题目,都多根经尝试一下quick select。
思路就是每次partition出来一个index, 计算[L, index]这个区间的sum和target的大小关系,来判断递归左边还是右边。区间sum在partition的过程中就可以算出来,所以其实就是一个quick select过程,没有其他额外开销。
[Note]
注意在getResult和getSum之间取index的不同,getSum取的区间应该是[L, index], 而getResult必须要从0开始,取[0, index]。
因为再递归过程中,如果当前sum < target, 递归右边的时候target会变成target – sum,就像kth smallest number那种做法一样,所以在getSum和target比较的时候,就是在当前[L, R]的期间里。
但是到了getResult, 情况就不一样了,必须得从0开始来对应最开始Input的target number.
[Code]
下面的code是quick select的算法,但是偷懒了getSum没有在partition的过程中算,这样的话时间复杂度可能和sort差不多。
// Quick Select, O(m), where m is the number of distinct words
class Solution2 {
  public Set<String> getWords(List<String> file, int target) {
    Set<String> result = new HashSet<>();
    if (file == null || file.isEmpty()) {
      return result;
    }
     
    Map<String, Integer> cntMap = new HashMap<>();
    for (String word : file) {
      cntMap.put(word, cntMap.getOrDefault(word, 0) + 1);
    }
     
    List<Map.Entry<String, Integer>> freq = new ArrayList<>(cntMap.entrySet());
     
    quickSelect(freq, 0, freq.size() - 1, target);
    return result;
  }
   
  private void quickSelect(List<Map.Entry<String, Integer>> freq, int l, int r, int target, Set<String> result) {
    if (l > r) {
      return;
    }
    if (l == r) {
      getResult(freq, 0, l, result);
      return
    }
     
    int index = partition(freq, l, r);
     
    int sum = getSum(freq, l, index);
    if (sum == target) {
      getResult(freq, 0, index, result);
    }
    else if (sum < target) {
      quickSelect(freq, index + 1, r, target - sum, result);
    }
    else {
      quickSelect(freq, l, index, sum, result);
    }
  }
   
  private int partition(List<Map.Entry<String, Integer>> freq, int l, int r) {
    int pivot = freq.get(l).getValue();
    int left = l;
    int right = r + 1;
    while (true) {
      while (++left < r && freq.get(left).getValue() < pivot);
      while (--right > l && freq.get(right).getValue() > pivot);
      if (left < right) {
        swap(freq, left, right);
      }
      else {
        break;
      }
    }
    swap(freq, l, rigth);
     
    return right;
  }
   
  private int getSum(List<Map.Entry<String, Integer>> freq, int l, int r) {
    int sum = 0;
    for (int i = l; i <= r; i++) {
      sum += freq.get(i).getValue();
    }
    return sum;
  }
   
  private void getResult(List<Map.Entry<String, Integer>> freq, int l, int r, Set<String> result) {
    for (int i = l; i <= r; i++) {
      result.add(freq.get(i).getKey());
    }
  }
}
Read full article from Google – Minimum Word Set with Frequency Sum Greater than Target

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