题目
- 从左往右遍历模型,当前要或者不要,要的条件是比之前的身高要高,然后返回所有情况中得分最高的
function process(heights, values, index, preHeight) {
if (index === heights.length) {
return 0;
}
const p1 = process(heights, values, index + 1, preHeight);
const p2 =
heights[index] > preHeight
? values[index] + process(heights, values, index + 1, heights[index])
: 0;
return Math.max(p1, p2);
}
- 进阶方式:使用线段树(因为支持更新和添加),将身高映射成索引,比如150=>1,160=>2,170=>3,通过线段树存储每一个身高结尾位置的最大值,当来到当前身高位置对应的索引时,假设为4,查找1-3的最大值,假设为3,查找1-2的最大值
public static int maxSum(int[] h, int[] v) {
int n = h.length;
int[] rank = new int[n];
for (int i = 0; i < n; i++) {
rank[i] = h[i];
}
Arrays.sort(rank);
SegmentTree st = new SegmentTree(n);
for (int i = 0; i < n; i++) {
int height = rank(rank, h[i]);
// 1~height max
st.update(height, st.max(height) + v[i]);
}
return st.max(n);
}
// [150, 152, 160, 175] 160
// 1 2 3 4
// 3
public static int rank(int[] rank, int num) {
int l = 0;
int r = rank.length - 1;
int m = 0;
int ans = 0;
while (l <= r) {
m = (l + r) / 2;
if (rank[m] >= num) {
ans = m;
r = m - 1;
} else {
l = m + 1;
}
}
return ans + 1;
}
public static class SegmentTree {
private int n;
private int[] max;
private int[] update;
public SegmentTree(int maxSize) {
n = maxSize + 1;
max = new int[n << 2];
update = new int[n << 2];
Arrays.fill(update, -1);
}
public void update(int index, int c) {
update(index, index, c, 1, n, 1);
}
public int max(int right) {
return max(1, right, 1, n, 1);
}
private void pushUp(int rt) {
max[rt] = Math.max(max[rt << 1], max[rt << 1 | 1]);
}
private void pushDown(int rt, int ln, int rn) {
if (update[rt] != -1) {
update[rt << 1] = update[rt];
max[rt << 1] = update[rt];
update[rt << 1 | 1] = update[rt];
max[rt << 1 | 1] = update[rt];
update[rt] = -1;
}
}
private void update(int L, int R, int C, int l, int r, int rt) {
if (L <= l && r <= R) {
max[rt] = C;
update[rt] = C;
return;
}
int mid = (l + r) >> 1;
pushDown(rt, mid - l + 1, r - mid);
if (L <= mid) {
update(L, R, C, l, mid, rt << 1);
}
if (R > mid) {
update(L, R, C, mid + 1, r, rt << 1 | 1);
}
pushUp(rt);
}
private int max(int L, int R, int l, int r, int rt) {
if (L <= l && r <= R) {
return max[rt];
}
int mid = (l + r) >> 1;
pushDown(rt, mid - l + 1, r - mid);
int ans = 0;
if (L <= mid) {
ans = Math.max(ans, max(L, R, l, mid, rt << 1));
}
if (R > mid) {
ans = Math.max(ans, max(L, R, mid + 1, r, rt << 1 | 1));
}
return ans;
}
}
// 为了测试
public static int[] randomArray(int n, int v) {
int[] ans = new int[n];
for (int i = 0; i < n; i++) {
ans[i] = (int) (Math.random() * v) + 1;
}
return ans;
}
// 为了测试
public static void main(String[] args) {
int N = 30;
int V = 100;
int testTime = 20000;
System.out.println("测试开始");
for (int i = 0; i < testTime; i++) {
int n = (int) (Math.random() * N) + 1;
int[] h = randomArray(n, V);
int[] v = randomArray(n, V);
if (right(h, v) != maxSum(h, v)) {
System.out.println("出错了!");
}
}
System.out.println("测试结束");
}