1.差分的基本概念:
如果有一数列 a[1],a[2],.…a[n] 且令 b[i]=a[i]-a[i-1],b[1]=a[1] 那么就有 a[i]=b[1]+b[2]+.…+b[i] =a[1]+a[2]-a[1]+a[3]-a[2]+.…+a[i]-a[i-1] 此时b数组称作a数组的差分数组 换句话来说a数组就是b数组的前缀和数组 例: 原始数组a:9 3 6 2 6 8 差分数组b:9 -6 3 -4 4 2 可以看到a数组是b的前缀和
那么现在有一个任务:
在区间[left,right]上加一个常数c。
我们可以利用原数组就是差分数组的前缀和这个特性,来解决这个问题。显然可得出公式:b[left]+=c,b[right+1]−=c
同样如果通过以上问题让求某一区间的和,那么前缀和也同样能够完成,但是如果操作的次数过大
那么前缀和显然会超时,但是同样有解决的方式例如 树状数组,线段树。
相对于代码长度而言,使用差分的思想求解会变得异常简单。
1.1.1 代表题目:1094. 拼车
public boolean carPooling(int[][] trips, int capacity) { int N = 1010, maxId = 0; int[] diff = new int[N]; int[] cap = new int[N]; for (int[] t : trips) { maxId = Math.max(maxId, t[1]); diff[t[1]] += t[0]; diff[t[2]] -= t[0]; } if (diff[0] > capacity) return false; cap[0] = diff[0]; for (int i = 1; i <= maxId; i++) { cap[i] = cap[i - 1] + diff[i]; if (cap[i] > capacity) return false; } return true; }
买卖股票的最佳时机 II
方法一:动态规划
public class MaxStockProfit { public static int maxProfit(int[] prices) { int len = prices.length; int[][] dp = new int[len][2]; dp[0][0] = 0; dp[0][1] = -prices[0]; for(int i=1; i<len; i++){ dp[i][0] = Math.max(dp[i-1][0], dp[i-1][1] + prices[i]); dp[i][1] = Math.max(dp[i-1][1], dp[i-1][0] - prices[i]); } return dp[len-1][0]; } public static int maxProfit2(int[] prices) { int len = prices.length; int dp0 = 0; int dp1 = -prices[0]; for(int i=1; i<len; i++){ dp0 = Math.max(dp0, dp1 + prices[i]); dp1 = Math.max(dp1, dp0 - prices[i]); } return dp0; } public static void main(String[] args) { int[] prices = {7,1,5,3,6}; System.out.println(maxProfit(prices)); System.out.println(maxProfit2(prices)); } }
方法二:贪心
public static int maxProfit3(int[] prices) {
int len = prices.length;
int ans = 0;
for(int i=1; i<len; i++){
ans += Math.max(0, prices[i] - prices[i-1]);
}
return ans;
}