modify code

pull/6/head
左程云 4 years ago
parent 1f4ab45ed5
commit 355cdbd84f

@ -1,9 +1,8 @@
package class20;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map.Entry;
import java.util.LinkedList;
// arr中的每个值都代表一张钱
// arr中都是正数aim>=0返回组成aim的最小张数
@ -29,6 +28,7 @@ public class Code04_MinCoinsOnePaper {
}
}
// dp1时间复杂度为O(arr长度 * aim)
public static int dp1(int[] arr, int aim) {
if (aim == 0) {
return 0;
@ -82,10 +82,12 @@ public class Code04_MinCoinsOnePaper {
return new Info(coins, zhangs);
}
// dp2时间复杂度为O(arr长度) + O(货币种数 * aim * 每种货币的平均张数)
public static int dp2(int[] arr, int aim) {
if (aim == 0) {
return 0;
}
// 得到info时间复杂度O(arr长度)
Info info = getInfo(arr);
int[] coins = info.coins;
int[] zhangs = info.zhangs;
@ -95,6 +97,7 @@ public class Code04_MinCoinsOnePaper {
for (int j = 1; j <= aim; j++) {
dp[N][j] = Integer.MAX_VALUE;
}
// 这三层for循环时间复杂度为O(货币种数 * aim * 每种货币的平均张数)
for (int index = N - 1; index >= 0; index--) {
for (int rest = 0; rest <= aim; rest++) {
dp[index][rest] = dp[index + 1][rest];
@ -110,95 +113,51 @@ public class Code04_MinCoinsOnePaper {
}
// 这种解法课上不讲
// 因为需要窗口内最大值和最小值的更新结构
// 因为需要理解窗口内最小值的更新结构
// 后面的课会讲
// dp3时间复杂度为O(arr长度) + O(货币种数 * aim)
public static int dp3(int[] arr, int aim) {
if (aim == 0) {
return 0;
}
// 得到info时间复杂度O(arr长度)
Info info = getInfo(arr);
int[] coins = info.coins;
int[] zhangs = info.zhangs;
int N = coins.length;
int[] c = info.coins;
int[] z = info.zhangs;
int N = c.length;
int[][] dp = new int[N + 1][aim + 1];
dp[N][0] = 0;
for (int j = 1; j <= aim; j++) {
dp[N][j] = Integer.MAX_VALUE;
}
int max = Integer.MIN_VALUE;
for (int i = 0; i < N; i++) {
max = Math.max(max, coins[i]);
// 虽然是嵌套了很多循环但是时间复杂度为O(货币种数 * aim)
// 因为用了窗口内最小值的更新结构
for (int i = N - 1; i >= 0; i--) {
for (int mod = 0; mod < Math.min(aim + 1, c[i]); mod++) {
LinkedList<Integer> w = new LinkedList<>();
w.add(mod);
dp[i][mod] = dp[i + 1][mod];
for (int r = mod + c[i]; r <= aim; r += c[i]) {
while (!w.isEmpty() && (dp[i + 1][w.peekLast()] == Integer.MAX_VALUE
|| dp[i + 1][w.peekLast()] + compensate(w.peekLast(), r, c[i]) >= dp[i + 1][r])) {
w.pollLast();
}
WindowBoss windows = new WindowBoss(max);
for (int index = N - 1; index >= 0; index--) {
windows.setDpCoinZhang(dp[index + 1], coins[index], zhangs[index]);
int rest = 0;
for (; rest < Math.min(aim + 1, coins[index]); rest++) {
windows.clearAdd(rest);
dp[index][rest] = dp[index + 1][rest];
}
for (; rest <= aim; rest++) {
windows.add(rest);
dp[index][rest] = windows.min(rest);
w.addLast(r);
int overdue = r - c[i] * (z[i] + 1);
if (w.peekFirst() == overdue) {
w.pollFirst();
}
dp[i][r] = dp[i + 1][w.peekFirst()] + compensate(w.peekFirst(), r, c[i]);
}
return dp[0][aim];
}
// 改进的窗口内最大值和最小值的更新结构
public static class WindowBoss {
public ArrayList<LinkedList<Integer>> windows;
private int[] dp;
private int coin;
private int zhang;
public WindowBoss(int maxValue) {
windows = new ArrayList<>();
for (int i = 0; i < maxValue; i++) {
windows.add(new LinkedList<>());
}
dp = null;
coin = 0;
zhang = 0;
return dp[0][aim];
}
private int offset(int pre, int cur) {
public static int compensate(int pre, int cur, int coin) {
return (cur - pre) / coin;
}
public void setDpCoinZhang(int[] d, int c, int z) {
dp = d;
coin = c;
zhang = z;
}
public void clearAdd(int rest) {
int windowi = rest % coin;
windows.get(windowi).clear();
windows.get(windowi).addLast(rest);
}
public void add(int rest) {
LinkedList<Integer> window = windows.get(rest % coin);
while (!window.isEmpty() && (dp[window.peekLast()] == Integer.MAX_VALUE
|| dp[window.peekLast()] + offset(window.peekLast(), rest) >= dp[rest])) {
window.pollLast();
}
window.addLast(rest);
int overdue = rest - coin * (zhang + 1);
if (window.peekFirst() == overdue) {
window.pollFirst();
}
}
public int min(int rest) {
LinkedList<Integer> window = windows.get(rest % coin);
int minIndex = window.peekFirst();
return dp[minIndex] + offset(minIndex, rest);
}
}
// 为了测试
public static int[] randomArray(int N, int maxValue) {
int[] arr = new int[N];
@ -287,7 +246,7 @@ public class Code04_MinCoinsOnePaper {
System.out.println("当货币很少出现重复dp2比dp3有常数时间优势");
System.out.println("当货币大量出现重复dp3时间复杂度明显优于dp2");
System.out.println("dp3的讲解放在窗口内最大值最小值的更新结构里");
System.out.println("dp3的讲解放在窗口内最大值最小值的更新结构里");
}
}

Loading…
Cancel
Save