1037. 有效的回旋镖
回旋镖定义为一组三个点,这些点各不相同且不在一条直线上。
给出平面上三个点组成的列表,判断这些点是否可以构成回旋镖。
示例 1:
输入:[[1,1],[2,3],[3,2]]
输出:true
示例 2:
输入:[[1,1],[2,2],[3,3]]
输出:false
提示:
1. points.length == 3
2. points[i].length == 2
3. 0 <= points[i][j] <= 100
思路:判断 即可。
class Solution {
public:
bool isBoomerang(vector<vector<int>>& points) {
return ((points[1][0] - points[0][0]) * (points[2][1] - points[0][1]) - (points[1][1] - points[0][1]) * (points[2][0] - points[0][0]));
}
};
1038. 从二叉搜索树到更大和树
给出二叉搜索树的根节点,该二叉树的节点值各不相同,修改二叉树,使每个节点 的新值等于原树中大于或等于 的值之和。
提醒一下,二叉搜索树满足下列约束条件:
- 节点的左子树仅包含键小于节点键的节点。
- 节点的右子树仅包含键大于节点键的节点。
- 左右子树也必须是二叉搜索树。
示例:
输入:[4,1,6,0,2,5,7,null,null,null,3,null,null,null,8]
输出:[30,36,21,36,35,26,15,null,null,null,33,null,null,null,8]
提示:
1. 树中的节点数介于 1 和 100 之间。
2. 每个节点的值介于 0 和 100 之间。
3. 给定的树为二叉搜索树。
思路:中序遍历的反向遍历,即先访问右子树,然后访问根、再访问左子树;访问根时加上当前节点的值 ,将当前节点的值 更改为
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
int sum;
TreeNode* bstToGst(TreeNode* root) {
if (root == nullptr)
return root;
dfs(root);
return root;
}
void dfs(TreeNode* root) {
if (root->right)
dfs(root->right);
sum += root->val;
root->val = sum;
if (root->left)
dfs(root->left);
}
};
1039. 多边形三角剖分的最低得分
给定 ,想象一个凸 边多边形,其顶点按顺时针顺序依次标记为 。
假设您将多边形剖分为 个三角形。对于每个三角形,该三角形的值是顶点标记的乘积,三角剖分的分数是进行三角剖分后所有 个三角形的值之和。
返回多边形进行三角剖分后可以得到的最低分。
示例 1:
输入:[1,2,3]
输出:6
解释:多边形已经三角化,唯一三角形的分数为 6。
示例 2:
输入:[3,7,4,5]
输出:144
解释:有两种三角剖分,可能得分分别为:3*7*5 + 4*5*7 = 245,或 3*4*5 + 3*4*7 = 144。最低分数为 144。
示例 3:
输入:[1,3,1,4,1,5]
输出:13
解释:最低分数三角剖分的得分情况为 1*1*3 + 1*1*4 + 1*1*5 + 1*1*1 = 13。
提示:
1. 3 <= A.length <= 50
2. 1 <= A[i] <= 100
思路:动态规划。 表示从第 个点到第 个点得到的最低分数三角剖分
- 当 时,也就是只含有两个点,此时不能剖分,则
- 当 时,也就是含有三个点,此时形成三角形,不能剖分,则 , 为中间点
- 当 时,此时如果在中间第 个点进行剖分,那么 ;即得到动态转移方程
class Solution {
public:
int dp[55][55];
const int INF = 1e9;
int minScoreTriangulation(vector<int>& A) {
int n = A.size();
//初始化dp数组
for (int i = 0; i < 55; ++i) {
for (int j = 0; j < 55; ++j)
dp[i][j] = INF;
}
//初始化两个点及三个点的情况
for (int i = 0; i < n - 1; ++i)
dp[i][i + 1] = 0;
for (int i = 0; i < n - 2; ++i)
dp[i][i + 2] = A[i] * A[i + 1] * A[i + 2];
for (int l = 3; l < n; ++l) { //中间相差l个点
for (int i = 0; i + l < n; ++i) {
int j = i + l;
//从k点剖分
for (int k = i + 1; k <= j - 1; ++k) {
dp[i][j] = min(dp[i][j], dp[i][k] + dp[k][j] + A[i] * A[k] * A[j]);
}
}
}
return dp[0][n - 1];
}
};
1040. 移动石子直到连续 II
在一个长度无限的数轴上,第 颗石子的位置为 。如果一颗石子的位置最小/最大,那么该石子被称作端点石子。
每个回合,你可以将一颗端点石子拿起并移动到一个未占用的位置,使得该石子不再是一颗端点石子。
值得注意的是,如果石子像 这样,你将无法移动位于位置 的端点石子,因为无论将它移动到任何位置(例如 或 ),该石子都仍然会是端点石子。
当你无法进行任何移动时,即,这些石子的位置连续时,游戏结束。
要使游戏结束,你可以执行的最小和最大移动次数分别是多少? 以长度为 的数组形式返回答案: _ , _ 。
示例 1:
输入:[7,4,9]
输出:[1,2]
解释:
我们可以移动一次,4 -> 8,游戏结束。
或者,我们可以移动两次 9 -> 5,4 -> 6,游戏结束。
示例 2:
输入:[6,5,4,3,10]
输出:[2,3]
解释:
我们可以移动 3 -> 8,接着是 10 -> 7,游戏结束。
或者,我们可以移动 3 -> 7, 4 -> 8, 5 -> 9,游戏结束。
注意,我们无法进行 10 -> 2 这样的移动来结束游戏,因为这是不合要求的移动。
示例 3:
输入:[100,101,104,102,103]
输出:[0,0]
提示:
1. 3 <= stones.length <= 10^4
2. 1 <= stones[i] <= 10^9
3. stones[i] 的值各不相同。
思路:将 排序。
- 1.最大移动次数即为一步步的移动;确定最大区间,因为移动端点,所以最大区间 ,总次数为最大区间长度,然后减去 个点移动到该区间即为最大移动次数
- 2.最小移动次数:先找能容纳所有元素的空间,即 ,计算移动次数 ;然后判断是否还有元素未连续,如果有则移动次数
class Solution {
public:
const int INF = 1e9;
vector<int> numMovesStonesII(vector<int>& stones) {
sort(stones.begin(), stones.end());
int n = stones.size();
int minstones = INF, maxstones = -INF;
for (int i = 0, j = 0; i < n; ++i) {
//找寻能容纳所有元素的空间
while (j + 1 < n && stones[j + 1] - stones[i] < n)
j++;
//计算移动步数
int ans = n - (j - i + 1);
//还有1个元素不连续的情况
if (ans == 1 && stones[j] - stones[i] == j - i &&
((j + 1 < n && (stones[j + 1] - stones[j] > 2)) || (i > 0 && stones[i] - stones[i - 1] > 2)))
ans++;
minstones = min(minstones, ans);
}
//最大步数计算
maxstones = max(stones[n - 1] - stones[1], stones[n - 2] - stones[0]) - (n - 2);
return {minstones, maxstones};
}
};