回旋镖定义为一组三个点,这些点各不相同且不在一条直线上。
给出平面上三个点组成的列表,判断这些点是否可以构成回旋镖。
示例1:
输入:[[1,1],[2,3],[3,2]]
输出:true
示例2:
输入:[[1,1],[2,2],[3,3]]
输出:false
提示:
points.length == 3
points[i].length == 2
0 <= points[i][j] <= 100
利用两点可以表示一条直线,判断第三点是否在直线上。公式如下:
y 2 − y 0 = y 1 − y 0 x 1 − x 0 ( x 2 − x 0 ) y_{2}-y_{0}=\frac{y_{1}-y_{0}}{x_{1}-x_{0}}(x_{2}-x{0}) y2−y0=x1−x0y1−y0(x2−x0)
( y 2 − y 0 ) ( x 1 − x 0 ) = ( y 1 − y 0 ) ( x 2 − x 0 ) (y_{2}-y_{0})(x_{1}-x_{0})=(y_{1}-y_{0})(x_{2}-x{0}) (y2−y0)(x1−x0)=(y1−y0)(x2−x0)
如果不在一条直线上,则上述第二个等式不成立
class Solution:
def isBoomerang(self, points: List[List[int]]) -> bool:
return (points[1][1]-points[0][1])*(points[2][0]-points[0][0])!=(points[1][0]-points[0][0])*(points[2][1]-points[0][1])
给出二叉搜索树的根节点,该二叉树的节点值各不相同,修改二叉树,使每个节点 node
的新值等于原树中大于或等于 node.val
的值之和。
二叉搜索树满足下列约束条件:
小于
节点键的节点。大于
节点键的节点。输入:[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]
提示:
观察给出的示例,可以看出,从最右侧叶子节点开始,进行先右后左的倒序中序遍历,即可实现目标。
/**
* 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:
TreeNode* bstToGst(TreeNode* root)
{
int cur=0;
InverseInOrder(root,cur);
return root;
}
void InverseInOrder(TreeNode* root,int& cur)
{
if(root)
{
InverseInOrder(root->right,cur);
cur+=root->val;
root->val=cur;
InverseInOrder(root->left,cur);
}
}
};
给定 N
,想象一个凸 N
边多边形,其顶点按顺时针顺序依次标记为 A[0], A[i], ..., A[N-1]
。
假设您将多边形剖分为 N-2
个三角形。对于每个三角形,该三角形的值是顶点标记的乘积,三角剖分的分数是进行三角剖分后所有 N-2
个三角形的值之和。
返回多边形进行三角剖分后可以得到的最低分。
示例1:
输入:[1,2,3]
输出:6
解释:多边形已经三角化,唯一三角形的分数为 6。
输入:[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。
提示:
3 <= A.length <= 50
1 <= A[i] <= 100
采用动态规划的方法。多边形任意两不相邻顶点连接形成一条边,将这个多边形分成两部分,至少有一部分是三角形。
可以令d[i][j]
是顶点A[i]
到A[j]之间的最小分数,枚举在(i,j)
之间的顶点k
和A[i]
,A[j]
形成三角形的分数。
动态规划方程为:
dp[i][j] = min(dp[i][j], dp[i][k] + dp[k][j] + A[i] * A[j] * A[k])
class Solution {
public:
int minScoreTriangulation(vector<int>& A)
{
int n=A.size();
int** dp=new int*[n];
for(int i=0;i<n;++i)
{
dp[i]=new int [n];
memset(dp[i],0,sizeof(int)*n);
}
for(int d=2;d<n;++d)
{
for(int i=0;i<n;++i)
{
if(i+d<n)
{
int j=i+d;
dp[i][j]=INT_MAX;
for(int k=i+1;k<j;++k)
dp[i][j]=min(dp[i][j],dp[i][k]+dp[k][j]+A[i]*A[j]*A[k]);
}
}
}
int ans=dp[0][n-1];
delete []dp;
return ans;
}
};
在一个长度无限的数轴上,第 i
颗石子的位置为 stones[i]
。如果一颗石子的位置最小/最大,那么该石子被称作端点石子。
每个回合,你可以将一颗端点石子拿起并移动到一个未占用的位置,使得该石子不再是一颗端点石子。
值得注意的是,如果石子像 stones = [1,2,5]
这样,你将无法移动位于位置 5 的端点石子,因为无论将它移动到任何位置(例如 0 或 3),该石子都仍然会是端点石子。
当你无法进行任何移动时,即,这些石子的位置连续时,游戏结束。
要使游戏结束,你可以执行的最小和最大移动次数分别是多少? 以长度为 2 的数组形式返回答案:answer = [minimum_moves, maximum_moves]
。
示例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]
提示:
3 <= stones.length <= 10^4
1 <= stones[i] <= 10^9
stones[i]
的值各不相同。每进行一轮操作,石子的左右端点的距离会缩短,一轮一轮收敛。最后会石子都紧邻游戏结束。
举个例子:
初始时有8颗石子,在数轴上的有石子的刻度为:
4,6,8,9,15,16,19,20
石子可以放置的空间,等于左右两端石子之间的未占用位置。在例子中,一共有20-4+1-8
个位置。
石子覆盖的线段长度是20-4
个,加上一个端点的位置即20-4+1
,再减去已经占用的8
个位置。
用公式表示为
s1=stones[n-1]-stones[0]+1-n
但是第一次移动的左端点或右端点的石子后,这个移动的石子和它相邻的那颗石子之间的空间,后面就不能被放置了,因为与他相邻的那个点变为端点,他们之间的位置不可以被放置了。
例如第一步移动了4,那么5这个位置就不可能放置石子了。所以要计算不能被访问的空间
s2=min(stones[n-1]-stones[n-2]-1, stones[1]-stones[0] -1)
最大值为s1-s2
。因为在后面的步骤里,我们都可以做出策略,让每一轮左右端点的差值只减1。
如果最后游戏结束,那么一定有n
个连续坐标摆满了石子。如果我们要移动最少,必定要找一个石子序列,使得在n
大小连续的坐标内,初始时有最多的石子。
设想有个尺子,上面有n
个刻度点,我们用这个尺子在石子从最左边到最右边移动,每动一次都查看下在尺子范围内有m
个石子,那么要使这个区间填满,就需要移动n-m
次。
只要在尺子外部有石子,就有策略填满尺子内的。
这些次数中最小的就为最少次数。
但是有一种特例:
1,2,3,4,7
这种1-4是最好的序列,但是7不能移动到端点,只能1先移动到6,然后7移动到5解决,这种情况要用2步。就是尺子内的石子都是连续的,中间没空洞,只在边上有空,要用2次。
class Solution {
public:
vector<int> numMovesStonesII(vector<int>& stones) {
sort(stones.begin(),stones.end());
int n = stones.size();
int mx = stones[n - 1] - stones[0] + 1 - n;
mx -= min(stones[n-1]-stones[n-2] - 1, stones[1]-stones[0] -1);
int mi = mx;
int i = 0;
int j = 0;
for(i = 0; i < n; ++i)
{
while(j + 1 < n && stones[j + 1] - stones[i] + 1 <= n)
++j;
int cost = n - (j - i + 1);
if(j - i + 1 == n - 1 && stones[j] - stones[i] + 1 == n - 1)
cost = 2;
mi = min(mi, cost);
}
return vector<int>{mi, mx};
}
};