[Algo] Maximum Expression Value 表达式最大值 - SegmentFault


[Algo] Maximum Expression Value 表达式最大值 - SegmentFault
给定一个整数数组,要求在数字之间任意添加乘号,加号和括号,使得最后表达式结果最大。比如1121,最大值为(1+1)*(2+1),所有数字都是正数。

时间O(n^2) 空间O(N^2)
先假设没有乘号,那最大值就是所有数加起来,然后我们考虑将其分段加入乘号,如果某一段是加号,和其他段相乘,那我们就认为那段加号的就被加了个括号。所以我们分段的过程其实就加了括号了。但是这么多数字我们可以分很多不同段,如果用搜索的话难免会有重复计算,所以这里用到动态规划,假设dp[i][j]表示总长为i的一段数字,其中前j长的哪一段中可以包含乘号,所能产生的最大值,这么一来,假设题目所给的数字有n个,那dp[n][n]就是这所有的数字组合起来既有加号又有乘号的式子的最大值了。再假设sum(k, i)表示所给数字从第k个到第i个数字的和。递推式为dp[i][j] = max(dp[i][j], dp[k][j - 1] * sum(k + 1, i)),这里i >= k >= j。其中后半部分dp[k][j - 1] * sum(k + 1, i)表示,我们把总长为i的数字分割成前k个,和k + 1到最后两部分。前半部分最大值已知,我们用它来乘以后半部分的和,用这种方法来决定哪一段只用加号。
举例说明,假设所给数字为
3 2 6
我们可以有最大值3 * 2 * 6 = 36,一开始我们有:
sum: 3 5 11
          j=0  j=1  j=2  j=3
dp:  i=0  0    0    0    0
     i=1  0    3    0    0
     i=2  0    5    0    0
     i=3  0    11   0    0
由于总长为i,其中前1位数字可以包含乘号的情况,就是所有数字都不包含乘号,所以最大值就是累加值。然后我们看总长为2开始(总长为1就是第一个数,没有计算的必要),前2位数字可以包含乘号的情况,这里我们可以有分割点k = 1时,是3 + 2 = 5k = 2时是3 * 2 = 6两种情况(k表示从第k位开始只有加号)。这时最大值6,更新dp[2][2]
          j=0  j=1  j=2  j=3
dp:  i=0  0    0    0    0
     i=1  0    3    0    0
     i=2  0    5    6    0
     i=3  0    11   0    0
然后我们看总长为3开始(总长为1就是第一个数,没有计算的必要),前2位数字可以包含乘号的情况。这里k=2时,3 * (2 + 6) = 24k=3时,6 * 6 = 36(第一个6是dp[2][2],第二个6是我们所给数字中的6)
          j=0  j=1  j=2  j=3
dp:  i=0  0    0    0    0
     i=1  0    3    0    0
     i=2  0    5    6    0
     i=3  0    11   24   36
更新完dp[3][3]我们也就计算完所有情况了,这时可知最大值是36.
全局最大max在第一个用于累加的for循环后,要置为dp[n][0],否则我们会把全部数字加起来这个组合给漏掉。
    public int solve(int[] nums){
        int n = nums.length;
        int[] sum = new int[n + 1];
        int[][] dp = new int[n + 1][n + 1];
        // 初始化累加数组,还有不用乘号的情况
        for(int idx = 1; idx <= n; idx++){
            sum[idx] = sum[idx - 1] + nums[idx - 1];
            dp[idx][1] = sum[idx];
        }
        int max = dp[n][0];
        // 对于总长为numOfDigitsInTotal的数字序列
        for(int numOfDigitsInTotal = 2; numOfDigitsInTotal <= n; numOfDigitsInTotal++){
            // 前numOfDigitsWithMult个数字可以包含乘号来计算的话
            for(int numOfDigitsWithMult = 2; numOfDigitsWithMult <= numOfDigitsInTotal; numOfDigitsWithMult++){
                // 从splitPointBetweenAddAndMult开始只用加号的话,求最大值
                for(int splitPointBetweenAddAndMult = numOfDigitsWithMult; splitPointBetweenAddAndMult <= numOfDigitsInTotal; splitPointBetweenAddAndMult++){
                    dp[numOfDigitsInTotal][numOfDigitsWithMult] = Math.max(dp[numOfDigitsInTotal][numOfDigitsWithMult],
                            dp[splitPointBetweenAddAndMult - 1][numOfDigitsWithMult - 1] * (sum[numOfDigitsInTotal] - sum[splitPointBetweenAddAndMult - 1]));
                }
                if(numOfDigitsInTotal == n && dp[n][numOfDigitsWithMult] > max){
                    max = dp[n][numOfDigitsWithMult];
                }
            }
        }
        return max;
    }
Maximum Expression Value II
给定一个整数数组,要求在数字之间任意添加乘号,加号和括号,使得最后表达式结果最大。比如1121,最大值为(1+1)*(2+1),这里数字可以是0或者负数。
解法和I是一样的,不过这里我们要维护一个最大表和一个最小表,这样,每次我们要乘的那个数是正数时,我们的最大值就是之前的最大值乘以这个正数,最小值就是之前的最小值乘以这个正数。如果要乘的是个负数的话,我们的最大值就是之前的最小值乘以这个正数,最小值就是之前的最大值乘以这个正数。另外,我们还要先初始化这个两个表,因为之前那题结果肯定大于0,所以我们不用初始化,不管怎么算原先矩阵中的0都会被替换掉。而本题中可以有0和负数,所以我们要把最大表先初始化为负最大值,最小表初始化为正最小值。

public int solve2(int[] nums){
    int n = nums.length;
    int[] sum = new int[n + 1];
    int[][] dpMax = new int[n + 1][n + 1];
    int[][] dpMin = new int[n + 1][n + 1];
    // 初始化最大表最小表
    for(int idx1 = 1; idx1 <=n; idx1++){
        for(int idx2 = 1; idx2 <=n; idx2++){
            dpMax[idx1][idx2] = Integer.MIN_VALUE;
        }
    }
    for(int idx1 = 1; idx1 <=n; idx1++){
        for(int idx2 = 1; idx2 <=n; idx2++){
            dpMin[idx1][idx2] = Integer.MAX_VALUE;
        }
    }
    // 初始化累加表
    for(int idx = 1; idx <= n; idx++){
        sum[idx] = sum[idx - 1] + nums[idx - 1];
        dpMax[idx][1] = sum[idx];
        dpMin[idx][1] = sum[idx];
    }
    int max = dpMax[n][1];
    for(int numOfDigitsInTotal = 2; numOfDigitsInTotal <= n; numOfDigitsInTotal++){
        for(int numOfDigitsWithMult = 2; numOfDigitsWithMult <= numOfDigitsInTotal; numOfDigitsWithMult++){
            for(int splitPointBetweenAddAndMult = numOfDigitsWithMult; splitPointBetweenAddAndMult <= numOfDigitsInTotal; splitPointBetweenAddAndMult++){
                int partialSum = sum[numOfDigitsInTotal] - sum[splitPointBetweenAddAndMult - 1];
                // 根据待会要乘的数的正负号,来判断我们乘的对象是最大表还是最小表
                if(partialSum < 0){
                    dpMax[numOfDigitsInTotal][numOfDigitsWithMult] = Math.max(dpMax[numOfDigitsInTotal][numOfDigitsWithMult],
                            dpMin[splitPointBetweenAddAndMult - 1][numOfDigitsWithMult - 1] * partialSum);
                    dpMin[numOfDigitsInTotal][numOfDigitsWithMult] = Math.min(dpMin[numOfDigitsInTotal][numOfDigitsWithMult],
                            dpMax[splitPointBetweenAddAndMult - 1][numOfDigitsWithMult - 1] * partialSum);
                } else {
                    dpMax[numOfDigitsInTotal][numOfDigitsWithMult] = Math.max(dpMax[numOfDigitsInTotal][numOfDigitsWithMult],
                            dpMax[splitPointBetweenAddAndMult - 1][numOfDigitsWithMult - 1] * partialSum);
                    dpMin[numOfDigitsInTotal][numOfDigitsWithMult] = Math.min(dpMin[numOfDigitsInTotal][numOfDigitsWithMult],
                            dpMin[splitPointBetweenAddAndMult - 1][numOfDigitsWithMult - 1] * partialSum);
                }
            }
            if(numOfDigitsInTotal == n && dpMax[n][numOfDigitsWithMult] > max){
                max = dpMax[n][numOfDigitsWithMult];
            }
        }
    }
    return max;
}
Q:如果输入是double数组怎么办?
A: 一样的做法,用第二题的解肯定没问题。
Read full article from [Algo] Maximum Expression Value 表达式最大值 - SegmentFault

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