动态规划

2020-02-14 DP - 4 - 划分型DP & 博弈型D

2020-02-16  本文已影响0人  边走边看边遗忘

划分型DP


Leetcode 279 - Perfect Squares
Given a positive integer n, find the least number of perfect square numbers (for example, 1, 4, 9, 16, ...) which sum to n.

Example 1:

Input: n = 12
Output: 3
Explanation: 12 = 4 + 4 + 4.
Example 2:

Input: n = 13
Output: 2
Explanation: 13 = 4 + 9.

    public int numSquares(int n) {
        if (n <= 1) {
            return 1;
        }    
        
        int[] dp = new int[n + 1];
        dp[0] = 0;
        dp[1] = 1;
        
        for (int i = 2; i <= n; i++) {
            dp[i] = Integer.MAX_VALUE;
           
            for (int j = 1; j * j <= i; j++) {
                if (dp[i - j * j] != Integer.MAX_VALUE) {
                    dp[i] = Math.min(dp[i], dp[i - j * j] + 1);
                }
            } 
        }
        
        return dp[n];
    }

Leetcode 132 - Palindrome Partitioning II

Given a string s, partition s such that every substring of the partition is a palindrome.

Return the minimum cuts needed for a palindrome partitioning of s.

Example:

Input: "aab"
Output: 1
Explanation: The palindrome partitioning ["aa","b"] could be produced using 1 cut.

Analysing the problem:

    public int minCut(String s) {
        if (s == null || s.length() == 0) {
            return 0;
        }            
        
        int length = s.length();
        int[] dp = new int[length + 1];
        boolean[][] isPalin = isPalindromicStr(s);
        
        for (int i = 1; i <= length; i++) {
            dp[i] = Integer.MAX_VALUE;
            
            for (int j = 1; j <= i; j++) {
                if (dp[j - 1] != Integer.MAX_VALUE && isPalin[j - 1][i - 1]) {
                    dp[i] = Math.min(dp[i], dp[j - 1]  + 1);
                }    
            }
        }
        
        return dp[length] - 1;
    }
    
    public boolean[][] isPalindromicStr(String s) {
        int length = s.length();    
        boolean[][] isPalin = new boolean[length][length];
        isPalin[0][0] = true;
        
        // length is odd
        for (int i = 0; i < length; i++) {
            isPalin[i][i] = true;
            
            int left = i - 1;
            int right = i + 1;
            while (left >= 0 && right < length && s.charAt(left) == s.charAt(right)) {
                isPalin[left][right] = true;    
                left--;
                right++;
            }    
        }
        
        // length is even 
        for (int i = 0; i < length; i++) {
            int left = i; 
            int right = i + 1;
            
            while (left >= 0 && right < length && s.charAt(left) == s.charAt(right)) {
                isPalin[left][right] = true;    
                left--;
                right++;
            }    
        }        
        
        return isPalin;
    }

Method 2:

    public int minCut(String s) {
        if (s == null || s.length() == 0) {
            return 0;
        }            
        
        int length = s.length();
        int[] dp = new int[length + 1];
        boolean[][] isPalin = isPalindromicStr(s);
        
        for (int i = 1; i <= length; i++) {
            dp[i] = Integer.MAX_VALUE;
            
            for (int j = 0; j < i; j++) {
                if (isPalin[j][i - 1]) {
                    dp[i] = Math.min(dp[i], dp[j]  + 1);
                }    
            }
        }
        
        return dp[length] - 1;
    }
    
    public boolean[][] isPalindromicStr(String s) {
        int length = s.length();    
        boolean[][] isPalin = new boolean[length][length];
  
        for (int i = 0; i < length; i++) {
            isPalin[i][i] = true;    
        }        
        
        for (int i = 0; i < length - 1; i++) {
            isPalin[i][i + 1] = (s.charAt(i) == s.charAt(i + 1));    
        } 
        
        for (int len = 2; len < length; len++) {
            for (int start = 0; start + len < length; start++) {
                isPalin[start][start + len] = isPalin[start + 1][start + len - 1] && 
                                              (s.charAt(start) == s.charAt(start + len));
            }    
        }
        
        return isPalin;
    }

Lintcode 437 - Copy Books

Description
Given n books and the i-th book has pages[i] pages. There are k persons to copy these books.

These books list in a row and each person can claim a continous range of books. For example, one copier can copy the books from i-th to j-th continously, but he can not copy the 1st book, 2nd book and 4th book (without 3rd book).

They start copying books at the same time and they all cost 1 minute to copy 1 page of a book. What's the best strategy to assign books so that the slowest copier can finish at earliest time?

Return the shortest time that the slowest copier spends.

The sum of book pages is less than or equal to 2147483647

Have you met this question in a real interview?
Example

Example 1:
Input: pages = [3, 2, 4], k = 2
Output: 5
Explanation:

Example 2:
Input: pages = [3, 2, 4], k = 3
Output: 4
Explanation: Each person copies one of the books.

Challenge
O(nk) time

Analysing the problem:

    public int copyBooks(int[] A, int K) {
        if (A == null || A.length == 0 || K == 0) {
            return 0;
        }
        
        int numOfPages = A.length;
        int[][] dp = new int[2][numOfPages + 1];
        int old = 0;
        int now = 1;
         
        for (int i = 0; i <= numOfPages; i++) {
            dp[now][i] = Integer.MAX_VALUE;     
        }
        
        dp[now][0] = 0;
        
        for (int i = 1; i <= K; i++) {
            old = now;    
            now = 1 - old;
            
            for (int j = 0; j <= numOfPages; j++) {
                dp[now][j] = Integer.MAX_VALUE;
                int sum = 0; 
                
                for (int k = j; k >= 0; k--) {
                    if (dp[old][k] != Integer.MAX_VALUE) {
                        dp[now][j] = Math.min(dp[now][j], Math.max(sum, dp[old][k]));
                    }
                    
                    if (k > 0) {
                        sum += A[k - 1];    
                    }
                }
            }
        }
        
        return dp[now][numOfPages];
    }

Lintcode 92 - Backpack

Given n items with size Ai, an integer m denotes the size of a backpack. How full you can fill this backpack?

Example
Example 1:
Input: [3,4,8,5], backpack size=10
Output: 9

Example 2:
Input: [2,3,5,7], backpack size=12
Output: 12

Challenge
O(n x m) time and O(m) memory.

O(n x m) memory is also acceptable if you do not know how to optimize memory.

Analysing the problem:

    public int backPack(int m, int[] A) {
        if (m == 0 || A == null || A.length == 0) {
            return 0;
        }        
        
        int length = A.length; 
        boolean[][] dp = new boolean[2][m + 1];
        int old = 0;
        int now = 1;
        
        dp[now][0] = true;
        
        for (int i = 1; i <= length; i++) {
            old = now;
            now = 1 - old;
            
            for (int w = 0; w <= m; w++) {
                dp[now][w] = dp[old][w]; 
                
                if (w - A[i - 1] >= 0) {
                    dp[now][w] |= dp[old][w - A[i - 1]];        
                }
            }
        }    
        
        for (int w = m; w >= 0; w--) {
            if (dp[now][w]) {
                return w;    
            }
        }
        
        return 0;
    }

Method 2:

    public int backPack(int m, int[] A) {
        if (m == 0 || A == null || A.length == 0) {
            return 0;
        }        
        
        // dp[w] represents while bag can handle w kg, the maximum weight can get 
        int[] dp = new int[m + 1];
        
        for (int i = 0; i < A.length; i++) {
            for (int w = m; w >= 0; w--) {
                if (w - A[i] >= 0) {
                    dp[w] = Math.max(dp[w], dp[w - A[i]] + A[i]);    
                }
            }
        }
        
        return dp[m];
    }
Summary

Lintcode 563 - Backpack V
Description
中文
English
Given n items with size nums[i] which an integer array and all positive numbers. An integer target denotes the size of a backpack. Find the number of possible fill the backpack.

Each item may only be used once

Have you met this question in a real interview?
Example
Given candidate items [1,2,3,3,7] and target 7,

A solution set is:
[7]
[1, 3, 3]
return 2

Analysing the problem:

    public int backPackV(int[] nums, int target) {
        if (nums == null || nums.length == 0) {
            return target == 0 ? 1 : 0;    
        }    
        
        int length = nums.length;  
        int[][] dp = new int[2][target + 1];
        int old = 0; 
        int now = 1;
        dp[now][0] = 1;    
        
        for (int i = 1; i <= length; i++) {
            old = now;
            now = 1 - old;
            
            for (int w = target; w >= 0; w--) {
                dp[now][w] = dp[old][w];
                
                if (w >= nums[i -1]) {
                    dp[now][w] += dp[old][w - nums[i - 1]];        
                }
            }
        }
        
        return dp[now][target];
    }

Space can be optimized again

calculation sequence1 that's why we can optimize
    public int backPackV(int[] nums, int target) {
        if (nums == null || nums.length == 0) {
            return target == 0 ? 1 : 0;    
        }    
        
        int length = nums.length;  
        int[] dp = new int[target + 1];
        dp[0] = 1;    
        
        for (int i = 1; i <= length; i++) {
            for (int w = target; w >= 0; w--) {
                dp[w] = dp[w];
                
                if (w >= nums[i -1]) {
                    dp[w] += dp[w - nums[i - 1]];        
                }
            }
        }
        
        return dp[target];
    }

Leetcode 377 - Combination Sum IV

Description

Given an integer array nums with all positive numbers and no duplicates, find the number of possible combinations that add up to a positive integer target.

A number in the array can be used multiple times in the combination.
Different orders are counted as different combinations.

Have you met this question in a real interview?
Example
Example1

Input: nums = [1, 2, 4], and target = 4
Output: 6
Explanation:
The possible combination ways are:
[1, 1, 1, 1]
[1, 1, 2]
[1, 2, 1]
[2, 1, 1]
[2, 2]
[4]

Example2

Input: nums = [1, 2], and target = 4
Output: 5
Explanation:
The possible combination ways are:
[1, 1, 1, 1]
[1, 1, 2]
[1, 2, 1]
[2, 1, 1]
[2, 2]

Analysing the problem:

    public int combinationSum4(int[] nums, int target) {
        if (nums == null || nums.length == 0) {
            return target == 0 ? 1 : 0;
        }        
        
        int[] dp = new int[target + 1];                 
        dp[0] = 1; 
        
        for (int i = 1; i <= target; i++) {
            for (int j = 0; j < nums.length; j++) {
                if (i >= nums[j]) {
                    dp[i] += dp[i - nums[j]];
                }
            }    
        }
        
        return dp[target];
    }

背包型DP总结

上一篇下一篇

猜你喜欢

热点阅读