给定n 个二元组(x,yi),(x2,y2)… (Xn,yn),已经按照x从小到大排好序了
重点来了,请问对于每个i,你都计算了哪些j和哪些算式?
这里有大量的冗余!
y1一X,y2一X,y3一x3的最大值明明已经在i =4的时候算过了,i =5为啥还要再算一遍呢?记temp = max y1一X1, y2- X2,y3一x3}
i =5时我们只需要计算max(temp, y4 -X4)
对于每个i,我们只需要让已有的temp与最新的“候选项”yi-1-xi-1取max !
刚才我们完成上面的优化,主要依靠两点:
在动态规划中经常遇到类似的式子,i是状态变量,j是决策变量
一旦发现冗余,或者有更高效维护“候选集合”的数据结构,就可以省去一层循环扫描!
把上面的问题形象化
你甚至可以发现它可以变成“树的直径”问题
×是树的主干
每个y都是树的分支
/
class Solution {
public:int findMaxValueOfEquation(vector<vector<int>>& points, int k) {SegmentTree tree(points);int res = INT_MIN;for(int j = 1; j < points.size(); j ++){// 找到横坐标 >= points[j][0] - k 的第一个索引 iint i = binary_search(points, j, points[j][0] - k);// 使用线段树求出 [i, j - 1] 区间的最大的 y - x 的值来更新答案if(i < j)res = max(res, points[j][1] + points[j][0]+ tree.query(i, j - 1));}return res;}private:// 使用二分搜索找到 ] 区间中横坐标 >= x 的第一个索引int binary_search(const vector<vector<int>>& points, int r, int x){int l = 0;while(l < r){int mid = (l + r) / 2;if(points[mid][0] < x) l = mid + 1;else r = mid;}return l;}
};
线段树部分如下:
class SegmentTree{private:int n;vector<int> data, tree;public:SegmentTree(const vector<vector<int>>& points) : n(points.size()), data(n), tree(4 * n){for(int i = 0; i < n; i ++)data[i] = points[i][1] - points[i][0];buildSegTree(0, 0, n - 1);}int query(int l, int r){return query(0, 0, n - 1, l, r);}private:void buildSegTree(int treeID, int l, int r){if(l == r){tree[treeID] = data[l];return;}int mid = (l + r) / 2;buildSegTree(treeID * 2 + 1, l, mid);buildSegTree(treeID * 2 + 2, mid + 1, r);tree[treeID] = max(tree[treeID * 2 + 1], tree[treeID * 2 + 2]);return;}int query(int treeID, int l, int r, int ql, int qr){if(ql == l && qr == r)return tree[treeID];int mid = (l + r) / 2;if(qr <= mid) return query(treeID * 2 + 1, l, mid, ql, qr);else if(ql > mid) return query(treeID * 2 + 2, mid + 1, r, ql, qr);int resl = query(treeID * 2 + 1, l, mid, ql, mid);int resr = query(treeID * 2 + 2, mid + 1, r, mid + 1, qr);return max(resl, resr);}
};
思路二:使用优先队列
class Solution {
public:int findMaxValueOfEquation(vector<vector<int>>& points, int k) {priority_queue<pair<int, int>> pq;// 初始放入第一个点的信息pq.push({points[0][1] - points[0][0], points[0][0]});int res = INT_MIN;for(int i = 1; i < points.size(); i ++){// 将优先队列队头不符合条件的点扔掉while(!pq.empty() && points[i][0] - pq.top().second > k) pq.pop();// 使用优先队列队首元素信息更新解if(!pq.empty())res = max(res, points[i][1] + points[i][0] + pq.top().first);// 将当前点的信息放入优先队列pq.push({points[i][1] - points[i][0], points[i][0]});}return res;}
};
思路三:使用红黑树
class Solution {
public:int findMaxValueOfEquation(vector<vector<int>>& points, int k) {set<pair<int, int>> tree;// 初始放入第一个点的信息tree.insert({points[0][1] - points[0][0], points[0][0]});int res = INT_MIN, j = 0;for(int i = 1; i < points.size(); i ++){// 删除红黑树中不满足条件的数据while(j < i && points[i][0] - points[j][0] > k){ase({points[j][1] - points[j][0], points[j][0]});j ++;}// 使用红黑树最大元素信息更新解if(!pty())res = max(res, points[i][1] + points[i][0] + tree.rbegin()->first);// 将当前点的信息放入红黑树tree.insert({points[i][1] - points[i][0], points[i][0]});}return res;}
};
完全把红黑树当优先队列用的代码如下(C++):
class Solution {
public:int findMaxValueOfEquation(vector<vector<int>>& points, int k) {set<pair<int, int>> tree;// 初始放入第一个点的信息tree.insert({points[0][1] - points[0][0], points[0][0]});int res = INT_MIN;for(int i = 1; i < points.size(); i ++){// 取出红黑树中的最大 y - x 值,如果不满足约束,则删除while(!pty() && points[i][0] - tree.rbegin()->second > ase(--d());// 使用红黑树最大元素信息更新解if(!pty())res = max(res, points[i][1] + points[i][0] + tree.rbegin()->first);// 将当前点的信息放入红黑树tree.insert({points[i][1] - points[i][0], points[i][0]});}return res;}
};
思路四:使用单调队列
class Solution {
public:int findMaxValueOfEquation(vector<vector<int>>& points, int k) {deque<pair<int, int>> dq;// 初始放入第一个点的信息dq.push_front({points[0][1] - points[0][0], points[0][0]});int res = INT_MIN;for(int i = 1; i < points.size(); i ++){// 对队列首不符合约束的点删除while(!dq.empty() && points[i][0] - dq.front().second > k)dq.pop_front();// 根据队首最大元素信息更新解if(!dq.empty())res = max(res, points[i][1] + points[i][0] + dq.front().first);// 把队列尾的比当前 y - x 还小的元素删除while(!dq.empty() && dq.back().first <= points[i][1] - points[i][0])dq.pop_back();// 将当前点的信息加入队列dq.push_back({points[i][1] - points[i][0], points[i][0]});}return res;}
};
/
class Solution {
public:int maxSubarraySumCircular(vector<int>& A) {int total = 0, maxSum = A[0], curMax = 0, minSum = A[0], curMin = 0;for (int& a : A) {curMax = max(curMax + a, a);maxSum = max(maxSum, curMax);curMin = min(curMin + a, a);minSum = min(minSum, curMin);total += a;}return maxSum > 0 ? max(maxSum, total - minSum) : maxSum;}};
class Solution {
public:int maxSubarraySumCircular(vector<int>& nums) {vector<int> cp(nums), sums(1, 0);for (auto& l : cp) nums.push_back(l);for (auto& l : nums) sums.push_back(sums.back() + l);deque<int> dq;dq.push_back(0);int ans = sums[1];for (int i = 1; i < sums.size(); i ++ ) {while (!dq.empty() && i - dq.front() > cp.size()) dq.pop_front();ans = max(ans, sums[i] - sums[dq.front()]);while (!dq.empty() && sums[dq.back()] >= sums[i]) dq.pop_back();dq.push_back(i); }return ans;}
};
给定一个由整数数组A表示的环形数组C,求C的非空子数组的最大可能和
请大家回顾之前学过的:
这道题是一个“区间型”环形动态规划
/
class Solution {
public:vector<vector<int>> rec;vector<int> val;public:int solve(int left, int right) {if (left >= right - 1) {return 0;}if (rec[left][right] != -1) {return rec[left][right];}for (int i = left + 1; i < right; i++) {int sum = val[left] * val[i] * val[right];sum += solve(left, i) + solve(i, right);rec[left][right] = max(rec[left][right], sum);}return rec[left][right];}int maxCoins(vector<int>& nums) {int n = nums.size();size(n + 2);for (int i = 1; i <= n; i++) {val[i] = nums[i - 1];}val[0] = val[n + 1] = size(n + 2, vector<int>(n + 2, -1));return solve(0, n + 1);}
};
class Solution {
public:int maxCoins(vector<int>& nums) {int n = nums.size();vector<vector<int>> rec(n + 2, vector<int>(n + 2));vector<int> val(n + 2);val[0] = val[n + 1] = 1;for (int i = 1; i <= n; i++) {val[i] = nums[i - 1];}for (int i = n - 1; i >= 0; i--) {for (int j = i + 2; j <= n + 1; j++) {for (int k = i + 1; k < j; k++) {int sum = val[i] * val[k] * val[j];sum += rec[i][k] + rec[k][j];rec[i][j] = max(rec[i][j], sum);}}}return rec[0][n + 1];}
};
C++ Code
/
class Solution {
public:int mergeStones(vector<int>& stones, int K) {int n = stones.size();if ((n - 1) % (K - 1) != 0) return -1;vector<int> prefix(n + 1);for (int i = 1; i <= n; ++i) {prefix[i] = prefix[i - 1] + stones[i - 1];}vector<vector<vector<int>>> f(n, vector<vector<int>>(n, vector<int>(K + 1, 0x3f3f3f3f)));for (int i = 0; i < n; ++i) {f[i][i][1] = 0;}for (int len = 2; len <= n; ++len) {for (int i = 0; i <= n - len; ++i) {int j = i + len - 1;for (int k = 2; k <= K; ++k) {for (int m = i; m < j; m += K - 1) {f[i][j][k] = min(f[i][j][k], f[i][m][1] + f[m + 1][j][k - 1]);}}f[i][j][1] = f[i][j][K] + prefix[j + 1] - prefix[i];}}return f[0][n - 1][1];}
};
class Solution {
public:int mergeStones(vector<int>& stones, int K) {int n = stones.size();if ((n - 1) % (K - 1) != 0) return -1;vector<int> prefix(n + 1);for (int i = 1; i <= n; ++i) {prefix[i] = prefix[i - 1] + stones[i - 1];}vector<vector<int>> f(n, vector<int>(n, 0x3f3f3f3f));for (int i = 0; i < n; ++i) {f[i][i] = 0;}for (int len = 2; len <= n; ++len) {for (int i = 0; i <= n - len; ++i) {int j = i + len - 1;for (int m = i; m < j; m += K - 1) {f[i][j] = min(f[i][j], f[i][m] + f[m + 1][j]);}if ((len - 1) % (K - 1) == 0) {f[i][j] += prefix[j + 1] - prefix[i];}}}return f[0][n - 1];}
};
=1041943
本文发布于:2024-01-28 19:39:22,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/17064419659795.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |