https://www.lintcode.com/problem/751
在一条数轴上,有n个城市,编号从0 ~ n – 1 , 约翰打算在这n个城市做点生意,他对Armani的一批货物感兴趣,每个城市对于这批货物都有一个价格prices[i]。对于城市x,约翰可从城市编号为[x - k, x + k]购买货物,然后卖到城市x,问约翰在每个城市最多能赚到多少钱?
prices.length 范围为[2, 100000], k <= 100000。
样例
样例1
输入: prices = [1, 3, 2, 1, 5] 和 k = 2
输出: [0, 2, 1, 0, 4]
解释:
i = 0,约翰可去的城市有0~2因为1、2号城市的价格比0号城市的价格高,所以赚不了钱,即 ans[0] = 0。
i = 1,可去的城市有0~3,可以从0号或者3号城市购买货物赚取的差价最大,即ans[1] = 2。
i = 2,可去的城市有0~4,显然从3号城市购买货物赚取的差价最大,即ans[2] = 1。
i = 3,可去的城市有1~4,没有其他城市的价格比3号城市价格低,所以赚不了钱,ans[3] = 0。
i = 4,可去的城市有2~4,从3号城市购买货物赚取的差价最大,即ans[4] = 4。
样例2
输入: prices = [1, 1, 1, 1, 1] 和 k = 1
输出: [0, 0, 0, 0, 0]
解释:
所有城市价格都一样,所以不能赚到钱,即所有的ans都为0。
线段树
public class Solution {
/**
* @param a: The prices [i]
* @param k:
* @return: The ans array
*/
public int[] business(int[] a, int k) {
int n = a.length;
int[] ans = new int[n];
SegmentNode root = build(0, n - 1, a);
for (int i = 0; i < n; i++) {
int left = i - k, right = i + k;
if (left < 0) left = 0;
if (right > n - 1) right = n - 1;
ans[i] = a[i] - query(root, left, right);
}
return ans;
}
static class SegmentNode { //线段树节点
int start, end, min;
SegmentNode left, right;
public SegmentNode(int s, int e) {
start = s;
end = e;
}
}
//创建线段树
public static SegmentNode build(int start, int end, int[] arr) {
if (start > end) return null;
if (start == end) {
SegmentNode nn = new SegmentNode(start, end);
nn.min = arr[start];
return nn;
}
SegmentNode root = new SegmentNode(start, end);
root.min = Integer.MAX_VALUE;
int mid = (start + end) / 2;
root.left = build(start, mid, arr);
root.right = build(mid + 1, end, arr);
if (root.left != null)
root.min = Math.min(root.min, root.left.min);
if (root.right != null)
root.min = Math.min(root.min, root.right.min);
return root;
}
//查询
public static int query(SegmentNode root, int start, int end) {
if (root.start == start && root.end == end) {
return root.min;
}
int mid = (root.start + root.end) / 2;
int left = Integer.MAX_VALUE;
int right = Integer.MAX_VALUE;
if (mid >= start) {
if (mid < end) {
left = query(root.left, start, mid);
} else {
left = query(root.left, start, end);
}
}
if (mid < end) {
if (mid >= start) {
right = query(root.right, mid + 1, end);
} else {
right = query(root.right, start, end);
}
}
return Math.min(left, right);
}
}