【Leetcode】第135场周赛

版权声明:本文为博主原创文章,转载请注明出处-- https://blog.csdn.net/qq_38790716/article/details/89925176

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 1 x 2 ! = y 2 x 1 y1*x2 != y2*x1 即可。

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. 从二叉搜索树到更大和树

给出二叉搜索树的根节点,该二叉树的节点值各不相同,修改二叉树,使每个节点 n o d e node 的新值等于原树中大于或等于 n o d e . v a l 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]

提示:

1. 树中的节点数介于 1100 之间。
2. 每个节点的值介于 0100 之间。
3. 给定的树为二叉搜索树。

思路:中序遍历的反向遍历,即先访问右子树,然后访问根、再访问左子树;访问根时加上当前节点的值 s u m sum ,将当前节点的值 r o o t &gt; v a l root-&gt;val 更改为 s u m sum

/**
 * 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. 多边形三角剖分的最低得分

给定 N N ,想象一个凸 N N 边多边形,其顶点按顺时针顺序依次标记为 A [ 0 ] , A [ i ] , . . . , A [ N 1 ] A[0], A[i], ..., A[N-1]

假设您将多边形剖分为 N 2 N-2 个三角形。对于每个三角形,该三角形的值是顶点标记的乘积,三角剖分的分数是进行三角剖分后所有 N 2 N-2 个三角形的值之和。

返回多边形进行三角剖分后可以得到的最低分。

示例 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

思路:动态规划。 d p [ i ] [ j ] dp[i][j] 表示从第 i i 个点到第 j j 个点得到的最低分数三角剖分

  • j i = 1 j - i = 1 时,也就是只含有两个点,此时不能剖分,则 d p [ i ] [ j ] = 0 dp[i][j] = 0
  • j i = 2 j - i = 2 时,也就是含有三个点,此时形成三角形,不能剖分,则 d p [ i ] [ j ] = A [ i ] A [ p ] A [ j ] dp[i][j] = A[i] * A[p] * A[j] p p 为中间点
  • j i = l j - i = l 时,此时如果在中间第 k k 个点进行剖分,那么 d p [ i ] [ j ] = d p [ i ] [ k ] + d p [ k ] [ j ] + A [ i ] A [ k ] A [ j ] dp[i][j] = dp[i][k] + dp[k][j] + A[i] * A[k] * A[j] ;即得到动态转移方程 d p [ i ] [ j ] = m i n ( d p [ i ] [ j ] , d p [ i ] [ k ] + d p [ k ] [ j ] + A [ i ] A [ k ] A [ j ] ) dp[i][j] = min(dp[i][j], dp[i][k] + dp[k][j] + A[i] * A[k] * A[j])
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

在一个长度无限的数轴上,第 i i 颗石子的位置为 s t o n e s [ i ] stones[i] 。如果一颗石子的位置最小/最大,那么该石子被称作端点石子。

每个回合,你可以将一颗端点石子拿起并移动到一个未占用的位置,使得该石子不再是一颗端点石子。

值得注意的是,如果石子像 s t o n e s = [ 1 , 2 , 5 ] stones = [1,2,5] 这样,你将无法移动位于位置 5 5 的端点石子,因为无论将它移动到任何位置(例如 0 0 3 3 ),该石子都仍然会是端点石子。

当你无法进行任何移动时,即,这些石子的位置连续时,游戏结束。

要使游戏结束,你可以执行的最小和最大移动次数分别是多少? 以长度为 2 2 的数组形式返回答案: a n s w e r = [ m i n i m u m answer = [minimum _ m o v e s moves , m a x i m u m maximum _ m o v e s ] moves]

示例 1:

输入:[7,4,9]
输出:[1,2]
解释:
我们可以移动一次,4 -> 8,游戏结束。
或者,我们可以移动两次 9 -> 54 -> 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] 的值各不相同。

思路:将 s t o n e s stones 排序。

  • 1.最大移动次数即为一步步的移动;确定最大区间,因为移动端点,所以最大区间 = m a x ( s t o n e s [ n 1 ] s t o n e s [ 1 ] , s t o n e s [ n 2 ] s t o n e s [ 0 ] ) =max(stones[n - 1] - stones[1], stones[n - 2] - stones[0]) ,总次数为最大区间长度,然后减去 ( n 2 ) (n - 2) 个点移动到该区间即为最大移动次数
  • 2.最小移动次数:先找能容纳所有元素的空间,即 s t o n e s [ j ] s t o n e s [ i ] &gt; = j i stones[j] - stones[i] &gt;= j - i ,计算移动次数 n ( j i + 1 ) n - (j - i + 1) ;然后判断是否还有元素未连续,如果有则移动次数 + 1 +1
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};
    }
};

猜你喜欢

转载自blog.csdn.net/qq_38790716/article/details/89925176
今日推荐