LeetCode 927 - Three Equal Parts


https://leetcode.com/problems/three-equal-parts/
Given an array A of 0s and 1s, divide the array into 3 non-empty parts such that all of these parts represent the same binary value.
If it is possible, return any [i, j] with i+1 < j, such that:
  • A[0], A[1], ..., A[i] is the first part;
  • A[i+1], A[i+2], ..., A[j-1] is the second part, and
  • A[j], A[j+1], ..., A[A.length - 1] is the third part.
  • All three parts have equal binary value.
If it is not possible, return [-1, -1].
Note that the entire part is used when considering what binary value it represents.  For example, [1,1,0] represents 6 in decimal, not 3.  Also, leading zeros are allowed, so [0,1,1] and [1,1] represent the same value.
Example 1:
Input: [1,0,1,0,1]
Output: [0,3]
Example 2:
Input: [1,1,0,1,1]
Output: [-1,-1]

Note:
  1. 3 <= A.length <= 30000
  2. A[i] == 0 or A[i] == 1
Approach 1: Equal Ones
Each part has to have the same number of ones in their representation. The algorithm given below is the natural continuation of this idea.
Algorithm
Say S is the number of ones in A. Since every part has the same number of ones, they all should have T = S / 3 ones.
If S isn't divisible by 3, the task is impossible.
We can find the position of the 1st, T-th, T+1-th, 2T-th, 2T+1-th, and 3T-th one. The positions of these ones form 3 intervals: [i1, j1], [i2, j2], [i3, j3]. (If there are only 3 ones, then the intervals are each length 1.)
Between them, there may be some number of zeros. The zeros after j3 must be included in each part: say there are z of them (z = S.length - j3).
So the first part, [i1, j1], is now [i1, j1+z]. Similarly, the second part, [i2, j2], is now [i2, j2+z].
If all this is actually possible, then the final answer is [j1+z, j2+z+1].
  • Time Complexity: O(N), where N is the length of S.
  • Space Complexity: O(N)
  public int[] threeEqualParts(int[] A) {
    int[] IMP = new int[] { -1, -1 };
    int N = A.length;

    int S = 0;
    for (int x : A)
      S += x;
    if (S % 3 != 0)
      return IMP;
    int T = S / 3;
    if (T == 0)
      return new int[] { 0, N - 1 };

    int i1 = -1, j1 = -1, i2 = -1, j2 = -1, i3 = -1, j3 = -1;
    int su = 0;
    for (int i = 0; i < N; ++i) {
      if (A[i] == 1) {
        su += 1;
        if (su == 1)
          i1 = i;
        if (su == T)
          j1 = i;
        if (su == T + 1)
          i2 = i;
        if (su == 2 * T)
          j2 = i;
        if (su == 2 * T + 1)
          i3 = i;
        if (su == 3 * T)
          j3 = i;
      }
    }

    // The array is in the form W [i1, j1] X [i2, j2] Y [i3, j3] Z
    // where [i1, j1] is a block of 1s, etc.
    int[] part1 = Arrays.copyOfRange(A, i1, j1 + 1);
    int[] part2 = Arrays.copyOfRange(A, i2, j2 + 1);
    int[] part3 = Arrays.copyOfRange(A, i3, j3 + 1);

    if (!Arrays.equals(part1, part2))
      return IMP;
    if (!Arrays.equals(part1, part3))
      return IMP;

    // x, y, z: the number of zeros after part 1, 2, 3
    int x = i2 - j1 - 1;
    int y = i3 - j2 - 1;
    int z = A.length - j3 - 1;

    if (x < z || y < z)
      return IMP;
    return new int[] { j1 + z, j2 + z + 1 };

  }
https://leetcode.com/problems/three-equal-parts/discuss/183902/Java-O(n)-Solution
// The solution can be optimized to O(1) space, by not using StringBuilder, but only record the index of  the first one digit of the right part.
    public int[] threeEqualParts(int[] A) {
        if (A == null || A.length < 3) return new int[] {-1, -1};
        int n = A.length;
        int cntOneBit = 0;
        
        for (int b : A) {
            if (b == 1) cntOneBit++;
        }
        if (cntOneBit % 3 != 0) return new int[] {-1, -1};
        
        int cnt = cntOneBit / 3;
        if (cnt == 0) return new int[] {0, n - 1};
    
        //construct the string using the right most part;
        int j = n - 1, cntR = 0;
        StringBuilder suffix = new StringBuilder();
        for (;j >= 0 && cntR < cnt; j--) {
            suffix.append(A[j]);
            if (A[j] == 1) cntR++;
         } 
    
        String target = suffix.reverse().toString();
        
        //matching the left part with target string, omit all leading zero
        int i = 0;
        while (A[i] == 0) i++;
    
        int k = 0;
        while (k < target.length()) {
            if (A[i + k] == target.charAt(k) - '0') k++;
            else return new int[] {-1, -1};
        }
        int left = i + k -1;
        
        //matching the middle part with target string, omit all leading zero
        i = i + k;
        while (A[i] == 0) i++;
        k = 0;
        while (k < target.length()) {
        if (A[i + k] == target.charAt(k) - '0') k++;
            else return new int[] {-1, -1};
        }    
        return new int[] {left, i + k}; 
    }

https://www.jianshu.com/p/c8dbaaf87644
这道题思考过程是这样,看了数据规模得出 解的时间复杂度应该是ON,那么暴力解法肯定不行。
O N + 分成3段,就想到2个指针。那么2个指针就很容易想到双向指针。
那么我就把第一个指针放在头部,后一个指针放在尾部,开始找能不能指针只会往中间走而不回退的方法。
我发现,如果一开始头尾指针构成的二进制数,如果是一样的。那么只要中间的部分和他们也是一样的就找到答案了。
如果不一样,分为2个情况
如果前面的 比 后面的 小
可以通过右移左指针而起到增大前面的本事。因为3个区间要相等。我们最开始已经贪心的把前后都压缩到最小,所以要补救势必是通过增大的方式。
如果后面比前面小。我们肯定要通过左移右指针去把中间的元素拿到右面,来增大右面。道理同上
如果配平了左右2面,此时一定是前缀和后缀长度最小的配平。根据贪心的思想。
我们就看这个最小的配平下,中间是不是也能配平。配平就找到解了。
如果中间的比右面的大,我们可以通过左移右指针,来试图让中间的区间减少。当然右移左指针也是可以的。为什么要选择左移右指针呢?
通过观察,右移左指针必然会使得前半部分增大。而左移右指针,可能因为是0,加了前缀0等于没加。而依然保持左半和右半配平。
如果中间的区间的值比右面的小,肯定无解了。因为我们已经为了配平左右而用了最小的长度。一旦要去从左右拿出元素,肯定就无法配平左右了。
分析到这里,思路就有了。
落实到代码,我决定用DQ,因为方便2头进出。
同时为了在做DQ compare的时候,加速。
我决定忽略所有前缀0,这增加了编码难度,但是加快了时间。
所有忽略前缀0的DQ,在比较的时候,
如果长度不同,可以直接比出大小。
如果长度相同,就依次遍历每一个值,如果全相同就同,如果一旦不同,直接比较这2个不同的值。
为了达到上述效果,我在发现每个DQ的前缀是0的情况下,就不插进去了。只有1做前缀的时候再插进去,同时需要补之前没插的0.




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