Leetcode 第135场周赛题目学习

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

参考思路

利用两点可以表示一条直线,判断第三点是否在直线上。公式如下:
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}) y2y0=x1x0y1y0(x2x0)
( 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}) (y2y0)(x1x0)=(y1y0)(x2x0)
如果不在一条直线上,则上述第二个等式不成立

参考代码

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])
        

1038.从二叉搜索树到更大和树

给出二叉搜索树的根节点,该二叉树的节点值各不相同,修改二叉树,使每个节点 node 的新值等于原树中大于或等于 node.val 的值之和。
二叉搜索树满足下列约束条件:

  • 节点的左子树仅包含键小于节点键的节点。
  • 节点的右子树仅包含键大于节点键的节点。
  • 左右子树也必须是二叉搜索树。

示例:
Leetcode 第135场周赛题目学习_第1张图片

输入:[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:
    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);
        }
        
    }
};

1039.多边形三角剖分的最低得分

给定 N,想象一个凸 N 边多边形,其顶点按顺时针顺序依次标记为 A[0], A[i], ..., A[N-1]
假设您将多边形剖分为 N-2 个三角形。对于每个三角形,该三角形的值是顶点标记的乘积,三角剖分的分数是进行三角剖分后所有 N-2 个三角形的值之和。
返回多边形进行三角剖分后可以得到的最低分。
示例1:

输入:[1,2,3]
输出:6
解释:多边形已经三角化,唯一三角形的分数为 6。

示例2:
Leetcode 第135场周赛题目学习_第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

参考思路

采用动态规划的方法。多边形任意两不相邻顶点连接形成一条边,将这个多边形分成两部分,至少有一部分是三角形。
可以令d[i][j]是顶点A[i]到A[j]之间的最小分数,枚举在(i,j)之间的顶点kA[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;
    }
};

1049.移动石子直到连续II

题目描述

在一个长度无限的数轴上,第 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]

提示:

  1. 3 <= stones.length <= 10^4
  2. 1 <= stones[i] <= 10^9
  3. 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};
    }
};

你可能感兴趣的:(Leetcode刷题-周赛)