zoukankan      html  css  js  c++  java
  • [LintCode] Stone Game II

    There is a stone game.At the beginning of the game the player picks n piles of stones in a circle.

    The goal is to merge the stones in one pile observing the following rules:

    At each step of the game,the player can merge two adjacent piles to a new pile.
    The score is the number of stones in the new pile.
    You are to determine the minimum of the total score.

    Example

    For [1, 4, 4, 1], in the best solution, the total score is 18:

    1. Merge second and third piles => [2, 4, 4], score +2
    2. Merge the first two piles => [6, 4],score +6
    3. Merge the last two piles => [10], score +10
    

    Other two examples:
    [1, 1, 1, 1] return 8
    [4, 4, 5, 9] return 43

    Solution.

    This is a follow up question of Stone Game I.  

    Inaddition to the regular non-circular case A[0], A[1]......A[n- 1], start index must be smaller than end index;

    When the n piles of stones are in a circle, start index can be bigger than end index. They are shown as follows.

    For n = 5, 

    Regular case: A[0], A[1], A[2], A[3], A[4]

    circular cases: A[4], A[0], A[1], A[2], A[3]

              A[1], A[2], A[3], A[4], A[0]

                         A[2], A[3], A[4], A[0], A[1]

                         A[3], A[4], A[0], A[1], A[2]

    Based on the above observation, start index can be any A[i] for i : [0.... n - 1], length of subproblems can be

    [2.......A.length]. 

    State:

    dp[start][end] still represents the min cost of merging A[start....end], end can be >= A.length, indicating a circular wrap.

    Function:

    end < A.length: dp[start][end] = min{dp[start][k] + dp[k + 1][end] + prefixSum[end + 1] - prefixSum[start]} for all k: [start, end]

    end >= A.length: dp[start][end % A.length] = min{dp[start][k % A.length] + dp[(k + 1) % A.length][end % A.length] + prefixSum[A.length]

                              - (prefixSum[(A.length + start) % A.length] - prefixSum[(end + 1) % A.length])}  for all k: [start, end]

    The formula in blue is the prefix sum of the circular subproblem of A[start...... end % A.length], we calculate this subtracting the continuous subarray in

    middle from the total sum of A.

    Initialization:

    dp[i][i] = 0;

    dp[i][j] = Integer.MAX_VALUE for all i != j;

    prefixSum[i]: the sum of the first ith elements of A;

    Answer:

    In Stone Game I, the answer is simply dp[0][A.length - 1];

    In Stone Game II, there are A.length of subproblems that have length A.length; 

    so the minimum of these n subproblems is the final minimal cost.

    Runtime: O(n^2)   (n - 2 + 1) * n, for each fixed length, we have n different start positions;

    Space: O(n^2)

     1 public class Solution {
     2     public int stoneGame2(int[] A) {
     3         if(A == null || A.length <= 1){
     4             return 0;
     5         }
     6         int[] prefixSum = new int[A.length + 1];
     7         prefixSum[0] = 0;
     8         for(int i = 1; i <= A.length; i++){
     9             prefixSum[i] = prefixSum[i - 1] + A[i - 1];
    10         }
    11         int[][] dp = new int[A.length][A.length];
    12         for(int i = 0; i < A.length; i++){
    13             for(int j = 0; j < A.length; j++){
    14                 dp[i][j] = Integer.MAX_VALUE;
    15             }
    16         }
    17         for(int i = 0; i < A.length; i++){
    18             dp[i][i] = 0;
    19         }
    20         for(int len = 2; len <= A.length; len++){
    21             for(int start = 0; start < A.length; start++){
    22                 int end = start + len - 1;
    23                 for(int k = start; k < end; k++){
    24                     if(end < A.length){
    25                         dp[start][end] = Math.min(dp[start][end], 
    26                         dp[start][k] 
    27                         + dp[k + 1][end] 
    28                         + prefixSum[end + 1] - prefixSum[start]);                        
    29                     }
    30                     else{
    31                         dp[start][end % A.length] = Math.min(dp[start][end % A.length], 
    32                         dp[start][k % A.length] 
    33                         + dp[(k + 1) % A.length][end % A.length] 
    34                         + prefixSum[A.length]
    35                         - (prefixSum[(A.length + start) % A.length] - prefixSum[(end + 1) % A.length] ));
    36                     }
    37                 }
    38             }
    39         }
    40         int min = Integer.MAX_VALUE;
    41         for(int i = 0; i < A.length; i++){
    42             min = Math.min(min, dp[i][(A.length - 1 + i) % A.length]);
    43         }
    44         return min;
    45     }
    46 }

    Related Problems

    Stone Game

  • 相关阅读:
    如何自己手写一个热加载(转)
    阻塞I/O、非阻塞I/O和I/O多路复用、怎样理解阻塞非阻塞与同步异步的区别?
    Java NIO浅析 转至 美团技术团队
    mysql在线修改表结构大数据表的风险与解决办法归纳(转)
    MySQL性能优化
    Tomcat Connector(BIO, NIO, APR)三种运行模式(转)
    redis 单线程的理解
    Spring 中的bean 是线程安全的吗?
    Spring 自定义注解,结合AOP,配置简单日志注解 (转)
    redis 分布式锁
  • 原文地址:https://www.cnblogs.com/lz87/p/6951217.html
Copyright © 2011-2022 走看看