【Lintcode】1322. Product Equal B
題目地址:
https://www.lintcode.com/problem/product-equal-b/description
給定一個長 n n n陣列 A A A,再給定一個數 b b b,每次可以花費 1 1 1的代價將序列中的某個數加 1 1 1或者減 1 1 1。問使得整個 A A A的乘積成為 b b b的最小代價。
思路是動態規劃。先求出 b b b的所有因子,設為其為陣列 f f f,即 f [ i ] f[i] f[i]是 b b b的從小到大的第 i + 1 i+1 i+1個因子。設 g [ k ] [ j ] g[k][j] g[k][j]是調整 A [ 0 : k ] A[0:k] A[0:k]這個子陣列使得 ∏ A [ 0 : k ] = f [ j ] \prod A[0:k]=f[j] ∏A[0:k]=f[j]的最小代價。若 s s s是 b b b的因子,設其座標是 m [ s ] m[s] m[s]。我們列舉 A [ k ] A[k] A[k]變成 s s s的情況, s s s取 b b b的所有因子。則有: g [ k ] [ j ] = min s ∣ b { g [ k − 1 ] [ m [ f [ j ] / s ] ] + ∣ A [ k ] − s ∣ } g[k][j]=\min_{s|b} \{g[k-1][m[f[j]/s]]+|A[k]-s|\} g[k][j]=s∣bmin{g[k−1][m[f[j]/s]]+∣A[k]−s∣}上式的含義是,我們考慮如果要將 A [ 0 : k ] A[0:k] A[0:k]的乘積變為 f [ j ] f[j] f[j]的最小代價。如果最後一個數要變成 s s s,則先要的代價是 ∣ A [ k ] − s ∣ |A[k]-s| ∣A[k]−s∣,此外要讓 A [ 0 : k − 1 ] A[0:k-1] A[0:k−1]的乘積變為 f [ j ] / s f[j]/s f[j]/s,當然 f [ j ] / s f[j]/s f[j]/s也是 b b b的因子,其在 f f f中的下標是 m [ f [ j ] / s ] m[f[j]/s] m[f[j]/s],所以調整 A [ 0 : k − 1 ] A[0:k-1] A[0:k−1]的乘積變為 f [ j ] / s f[j]/s f[j]/s的最小代價是 g [ k − 1 ] [ m [ f [ j ] / s ] ] g[k-1][m[f[j]/s]] g[k−1][m[f[j]/s]]。 s s s取遍所有 b b b的因子就得到了 g [ k ] [ j ] g[k][j] g[k][j]。初始條件 g [ 0 ] [ j ] = ∣ A [ 0 ] − f [ j ] ∣ g[0][j]=|A[0]-f[j]| g[0][j]=∣A[0]−f[j]∣。程式碼如下:
import java.util.*;
public class Solution {
/**
* @param B: the all Ai product equal to B
* @param A: the positive int array
* @return: return the minium cost
*/
public int getMinCost(int B, int[] A) {
// write your code here
List<Integer> fac = new ArrayList<>();
Map<Integer, Integer> map = new HashMap<>();
// 求B的所有因子,存入fac列表,並用map記錄每個因子在fac中的下標
for (int i = 1; i <= B; i++) {
if (B % i == 0) {
fac.add(i);
map.put(i, fac.size() - 1);
}
}
int n = fac.size();
// dp[k][i]是調整A[0 : k]使得整個乘積是fac[i]的最小代價
int[][] dp = new int[A.length][n];
for (int i = 0; i < dp[0].length; i++) {
dp[0][i] = Math.abs(A[0] - fac.get(i));
}
for (int i = 1; i < A.length; i++) {
// 先初始化為正無窮
Arrays.fill(dp[i], Integer.MAX_VALUE);
// 列舉A[0 : i]的乘積是fac[j]
for (int j = 0; j < n; j++) {
// 列舉最後一個數調整為fac[k]
for (int k = 0; k <= j; k++) {
if (fac.get(j) % fac.get(k) == 0) {
dp[i][j] = Math.min(dp[i][j], dp[i - 1][map.get(fac.get(j) / fac.get(k))] + Math.abs(A[i] - fac.get(k)));
}
}
}
}
return dp[A.length - 1][n - 1];
}
}
時間複雜度 O ( b + n k 2 ) O(b+nk^2) O(b+nk2), k k k是 b b b的因子個數,空間 O ( n k ) O(nk) O(nk)。
可以用滾動陣列優化。程式碼如下:
import java.util.*;
public class Solution {
/**
* @param B: the all Ai product equal to B
* @param A: the positive int array
* @return: return the minium cost
*/
public int getMinCost(int B, int[] A) {
// write your code here
List<Integer> fac = new ArrayList<>();
Map<Integer, Integer> map = new HashMap<>();
for (int i = 1; i <= B; i++) {
if (B % i == 0) {
fac.add(i);
map.put(i, fac.size() - 1);
}
}
int n = fac.size();
int[][] dp = new int[2][n];
for (int i = 0; i < dp[0].length; i++) {
dp[0][i] = Math.abs(A[0] - fac.get(i));
}
for (int i = 1; i < A.length; i++) {
Arrays.fill(dp[i & 1], Integer.MAX_VALUE);
for (int j = 0; j < n; j++) {
for (int k = 0; k <= j; k++) {
if (fac.get(j) % fac.get(k) == 0) {
dp[i & 1][j] = Math.min(dp[i & 1][j], dp[i - 1 & 1][map.get(fac.get(j) / fac.get(k))] + Math.abs(A[i] - fac.get(k)));
}
}
}
}
return dp[A.length - 1 & 1][n - 1];
}
}
時間複雜度不變,空間 O ( n ) O(n) O(n)。
相關文章
- [LeetCode/LintCode] Largest Palindrome ProductLeetCode
- 【Lintcode】1415. Residual Product
- 【Lintcode】191. Maximum Product Subarray
- B. Equal XOR
- CF.1416B. Make Them Equal
- Ruby Struct EqualStruct
- Product Quantization
- A. Least ProductAST
- [LintCode] Daily TemperaturesAI
- [LintCode] Permutation in String
- ABC 322 E Product Developmentdev
- SAP EPD - Enterprise Product Developmentdev
- [LeetCode] 416. Partition Equal Subset SumLeetCode
- [LeetCode] 2831. Find the Longest Equal SubarrayLeetCode
- cf1417-D. Make Them Equal
- [LintCode/LeetCode] Meeting RoomsLeetCodeOOM
- Lintcode 1263. Is Subsequence
- 【Lintcode】1189. Minesweeper
- 238. Product of Array Except Self
- LeetCode | 152. Maximum Product SubarrayLeetCode
- 318-Maximum Product of Word Lengths
- [LeetCode] 2491. Divide Players Into Teams of Equal SkillLeetCodeIDE
- 【Leetcode】453. Minimum Moves to Equal Array ElementsLeetCode
- [LintCode/LeetCode] Contains Duplicate IIILeetCodeAI
- [LintCode] Check Full Binary Tree
- [LintCode/LeetCode] Remove Duplicate LettersLeetCodeREM
- [LintCode] 3Sum Smaller
- 【Lintcode】1615. The Result of Investment
- [LintCode] Binary Tree Level Order
- 【Lintcode】1736. Throw Garbage
- 【Lintcode】1665. Calculate Number
- 【Lintcode】1789. Distinguish UsernameNGUI
- 【Lintcode】1562. Number of RestaurantsREST
- 【Lintcode】576. Split Array
- 【Lintcode】1267. Lexicographical Numbers
- 【Lintcode】141. Sqrt(x)
- 【Lintcode】1230. Assign CookiesCookie
- 【Lintcode】1732. Snakes and Ladders