Lintcode: Sort Colors II 解题报告 - Yu's Garden - 博客园


Lintcode: Sort Colors II 解题报告 - Yu's Garden - 博客园
Given an array of n objects with k different colors (numbered from 1 to k), sort them so that objects of the same color are adjacent, with the colors in the order 1, 2, ... k.
Notice
You are not suppose to use the library's sort function for this problem.
k <= n
Example
Given colors=[3, 2, 2, 1, 4]k=4, your code should sort colors in-place to [1, 2, 2, 3, 4].
Challenge
A rather straight forward solution is a two-pass algorithm using counting sort. That will cost O(k) extra memory. Can you do it without using extra memory?
https://xuezhashuati.blogspot.com/2017/04/lintcode-143-sort-colors-ii.html
用3-way-partition的方法,每次把比k小的数字放到前面,把比k大的数字放到后面。
然后递归去排比k小的数字和比k大的数字。
时间复杂度是O(nlogk)。
    public void sortColors2(int[] colors, int k) {        
        if (colors == null || colors.length == 0) {
            return ;
        }
        
        partition(colors, 0, colors.length - 1, 1, k);
    }
    
    public void partition(int nums[], int lo, int hi, int lowNum, int hiNum) {
        if (lowNum == hiNum) {
            return;
        }
        
        if (lo >= hi) {
            return;
        }
        
        int lt = lo;
        int gt = hi;
        int v = (lowNum + hiNum) / 2;
        int i = lt;
        while (i <= gt) {
            if (nums[i] < v) {
                exch(nums, lt++, i++);
            }
            else if (nums[i] > v) {
                exch(nums, i, gt--);
            }
            else {
                i++;
            }
        }
        
        partition(nums, lo, lt - 1, lowNum, v - 1);
        partition(nums, gt, hi, v + 1, hiNum);
    }
    
    public void exch(int[] nums, int x, int y) {
        int tmp = nums[x];
        nums[x] = nums[y];
        nums[y] = tmp;
    }
http://www.jiuzhang.com/solutions/sort-colors-ii/
// version 1: O(nlogk), the best algorithm based on comparing

    public void sortColors2(int[] colors, int k) {
        if (colors == null || colors.length == 0) {
            return;
        }
        rainbowSort(colors, 0, colors.length - 1, 1, k);
    }
    
    public void rainbowSort(int[] colors,
                            int left,
                            int right,
                            int colorFrom,
                            int colorTo) {
        if (colorFrom == colorTo) {
            return;
        }
        
        if (left >= right) {
            return;
        }
        
        int colorMid = (colorFrom + colorTo) / 2;
        int l = left, r = right;
        while (l <= r) {
            while (l <= r && colors[l] <= colorMid) {
                l++;
            }
            while (l <= r && colors[r] > colorMid) {
                r--;
            }
            if (l <= r) {
                int temp = colors[l];
                colors[l] = colors[r];
                colors[r] = temp;
                
                l++;
                r--;
            }
        }
        
        rainbowSort(colors, left, r, colorFrom, colorMid);
        rainbowSort(colors, l, right, colorMid + 1, colorTo);
    }

// version 2: O(nk), not efficient, will get Time Limit Exceeded error. But you should try to implement the following algorithm for practicing purpose.
    public void sortColors2(int[] colors, int k) {
        int count = 0;
        int start = 0;
        int end = colors.length - 1;
        while (count < k) {
            int min = Integer.MAX_VALUE;
            int max = Integer.MIN_VALUE;
            
            for (int i = start; i <= end; i++) {
                min = Math.min(min, colors[i]);
                max = Math.max(max, colors[i]);
            }
            int left = start;
            int right = end;
            int cur = left;
            while(cur <= right) {
                if (colors[cur] == min) {
                    swap(left, cur, colors);
                    cur++;
                    left++;
                } else if (colors[cur] > min && colors[cur] < max) {
                    cur++;
                } else {
                    int tmp = colors[cur];
                    swap(cur, right, colors);
                    right--;
                }
            }
            count += 2;
            start = left;
            end = right;
        }
    }
    
    void swap(int left, int right, int[] colors) {
        int tmp = colors[left];
        colors[left] = colors[right];
        colors[right] = tmp;
    }
https://codesolutiony.wordpress.com/2015/05/28/lintcode-sort-colors-ii/
简单的办法可以利用two pass, 相当于counting sort,计数每个color的个数,再依次填入到原来的array中;这种方法空间复杂度为 O(k), 时间复杂度为 O(n)。
Count sort, 扫两遍即可,需要O(k)的空间
    public void sortColors2(int[] colors, int k) {
        int[] count = new int[k];
        for (int color : colors) {
            count[color-1]++;
        }
        int index = 0;
        for (int i = 0; i < k; i++) {
            while (count[i]>0) {
                colors[index++] = i+1;
                count[i]--;
            }
        }
    }
用two pointers办法,每次只能sort出两端的两个数字,因此复杂度比较高O(k/2*n)
    public void sortColors2(int[] colors, int k) {
        int start = -1;
        int end = colors.length;
        for (int round = 1; round*2 <= k; round++) {
            int leftColor = round;
            int rightColor = k - round + 1;
            for (int index = start+1; index < end; index++) {
                if (colors[index] == leftColor) {
                    colors[index] = colors[++start];
                    colors[start] = leftColor;
                } else if (colors[index] == rightColor) {
                    colors[index] = colors[--end];
                    colors[end] = rightColor;
                    index--;
                }
            }
        }
    }
使用快排,时间复杂度是O(nlogn),空间复杂度是O(Log(N))
 9     public void sortKColors1(int[] colors, int k) {
10         // write your code here
11         if (colors == null) {
12             return;
13         }
14         
15         quickSort(colors, 0, colors.length - 1);
16     }
17     
18     public void quickSort(int[] colors, int left, int right) {
19         if (left >= right) {
20             return;
21         }
22         
23         int pivot = colors[right];
24         
25         int pos = partition(colors, left, right, pivot);
26         
27         quickSort(colors, left, pos - 1);
28         quickSort(colors, pos + 1, right);
29     }
30     
31     public int partition(int[] colors, int left, int right, int pivot) {
32         int leftPoint = left - 1;
33         int rightPoint = right;
34         
35         while (true) {
36             while (colors[++leftPoint] < pivot);
37             
38             while (leftPoint < rightPoint && colors[--rightPoint] > pivot);
39             
40             if (leftPoint >= rightPoint) {
41                 break;
42             }
43             
44             swap(colors, leftPoint, rightPoint);
45         }
46         
47         swap(colors, leftPoint, right);
48         return leftPoint;
49     }
Doing quick sort partition for K -1 times.
1. Use K - 1 value as pivot
2. Starting from 0, whenever low<high && less or equal to pivot, low++
3. starting from end, whenever high >0, and greater than pivot, high--
4. Result: only swap when low and high have disagreement on the pivot value.
public void sortColors2(int[] colors, int k) {
    if (colors == null || colors.length == 0 || k <= 0) {
        return;
    }
    int end = colors.length - 1;
    for (int i = 0; i < k - 1; i++) {
        end = helper(colors, 0, end, k - i - 1);
    }
}
public int helper(int[] colors, int start, int end, int pivot) {
    int low = start;
    int high = end;
    while (low <= high) {
        while(low < high && colors[low] <= pivot) {
            low++;
        }
        while(high > 0 && colors[high] > pivot) {
            high--;
        }
        if (low <= high) {
            swap(colors, low, high);
            low++;
            high--;
        }
    }
    return low - 1;
}
X. http://www.jianshu.com/p/9bad070d7802
  • 这道题原数组还要重复利用作为bucket数组!!! 首先for循环遍历一遍原来的数组,如果扫到a[i],首先检查a[a[i]]是否为正数,如果是把a[a[i]]移动a[i]存放起来,然后把a[a[i]]记为-1(表示该位置是一个计数器,计1)。 如果a[a[i]]是负数,那么说明这一个地方曾经已经计数了,那么把a[a[i]]计数减一,并把color[i] 设置为0 (表示此处已经计算过),然后重复向下遍历下一个数,这样遍历原数组所有的元素过后,数组a里面实际上存储的每种颜色的计数,然后我们倒着再输出每种颜色就可以得到我们排序后的数组。
    例子(按以上步骤运算):
    3 2 2 1 4
    2 2 -1 1 4
    2 -1 -1 1 4
    0 -2 -1 1 4
    -1 -2 -1 0 4
    -1 -2 -1 -1 0
    def sortColors2(self, colors, k):
        if not colors:
            return

        for i in range(len(colors)):
            while colors[i] > 0:
                num = colors[i]
                if colors[num - 1] > 0:
                    colors[i] = colors[num - 1]
                    colors[num - 1] = -1
                elif colors[num - 1] <= 0:
                    colors[num - 1] -= 1
                    colors[i] = 0

        index = len(colors) - 1
        for i in range(k - 1, -1, -1):
            temp = colors[i]
            while temp < 0:
                colors[index] = i + 1
                temp += 1
                index -= 1

inplace,并且O(N)时间复杂度的算法。
我们可以使用类似桶排序的思想,对所有的数进行计数。
1. 从左扫描到右边,遇到一个数字,先找到对应的bucket.比如
3 2 2 1 4
第一个3对应的bucket是index = 2 (bucket从0开始计算)
2. Bucket 如果有数字,则把这个数字移动到i的position(就是存放起来),然后把bucket记为-1(表示该位置是一个计数器,计1)。
3. Bucket 存的是负数,表示这个bucket已经是计数器,直接减1. 并把color[i] 设置为0 (表示此处已经计算过)
4. Bucket 存的是0,与3一样处理,将bucket设置为-1, 并把color[i] 设置为0 (表示此处已经计算过)
5. 回到position i,再判断此处是否为0(只要不是为0,就一直重复2-4的步骤)。
6.完成1-5的步骤后,从尾部到头部将数组置结果。(从尾至头是为了避免开头的计数器被覆盖)
例子(按以上步骤运算):
3 2 2 1 4
2 2 -1 1 4
2 -1 -1 1 4
0 -2 -1 1 4
-1 -2 -1 0 4
-1 -2 -1 -1 0
2     public void sortKColors(int[] colors, int k) {
 4         if (colors == null) {
 5             return;
 6         }
 7         
 8         int len = colors.length;
 9         for (int i = 0; i < len; i++) {
10             // Means need to deal with A[i]
11             while (colors[i] > 0) {
12                 int num = colors[i];
13                 if (colors[num - 1] > 0) {    
14                     // 1. There is a number in the bucket, 
15                     // Store the number in the bucket in position i;
16                     colors[i] = colors[num - 1];
17                     colors[num - 1] = -1;
18                 } else if (colors[num - 1] <= 0) {
19                     // 2. Bucket is using or the bucket is empty.
20                     colors[num - 1]--;
21                     // delete the A[i];
22                     colors[i] = 0;
23                 }
24             }
25         }
26         
27         int index = len - 1;
28         for (int i = k - 1; i >= 0; i--) {
29             int cnt = -colors[i];
30             
31             // Empty number.
32             if (cnt == 0) {
33                 continue;
34             }
35                                 
36             while (cnt > 0) {
37                 colors[index--] = i + 1;
38                 cnt--;
39             }
40         }

http://blog.csdn.net/nicaishibiantai/article/details/43306431
为了省空间,只能花时间了,还是按照sort color的方法,找到当前array中min, max,其余忽略,然后把min/max放到最前和最后。循环直到min/max count = k
复杂度是O(n^2): T(n) = T(n-2) + n
    public void sortColors2(int[] colors, int k) {
        int count = 0;
        int start = 0;
        int end = colors.length-1;
        while (count < k) {
            int min = Integer.MAX_VALUE;
            int max = Integer.MIN_VALUE;
            
            for (int i = start; i < end; i++) {
                min = Math.min(min, colors[i]);
                max = Math.max(max, colors[i]);
            }
            int left = start;
            int right = end;
            int cur = left;
            while(cur <= right) {
                if (colors[cur] == min) {
                    swap(left, cur, colors);
                    cur++;
                    left++;
                } else if (colors[cur] > min && colors[cur] < max) {
                    cur++;
                } else {
                    int tmp = colors[cur];
                    swap(cur, right, colors);
                    right--;
                }
            }
            count += 2;
            start = left;
            end = right;
        }
    }
https://github.com/shawnfan/LintCode/blob/master/Java/Sort%20Colors%20II.java
Read full article from Lintcode: Sort Colors II 解题报告 - Yu's Garden - 博客园

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