Leetcode第132场周赛题目学习

5024.除数博弈

题目描述

爱丽丝和鲍勃一起玩游戏,他们轮流行动。爱丽丝先手开局。
最初,黑板上有一个数字 N 。在每个玩家的回合,玩家需要执行以下操作:

  • 选出任一 x,满足 0 < x < NN % x == 0
  • N - x 替换黑板上的数字 N

如果玩家无法执行这些操作,就会输掉游戏。
只有在爱丽丝在游戏中取得胜利时才返回 True,否则返回 false。假设两个玩家都以最佳状态参与游戏。
示例1:

输入:2
输出:true
解释:爱丽丝选择 1,鲍勃无法进行操作。

示例2:

输入:3
输出:false
解释:爱丽丝选择 1,鲍勃也选择 1,然后爱丽丝无法进行操作。

解题思路

如果当前数N对于爱丽丝先手为胜,则对于爱丽丝后手则为负,故对于一个新的数N,爱丽丝需要选择一个合适的除数x,使得N-x后新的N对鲍勃来说为负,如此方可胜利。
因此,对于N,遍历N的除数,然后判断N-x的结果是否为负,若存在一个x,使得N-x为胜,则爱丽丝可以获胜。
现已知N=2时,爱丽丝胜,N=3时,爱丽丝负。则当N=4时,满足要求的除数有12。当爱丽丝选择1时,N=N-1=3。因为N=3时,先手的无论怎么选,都是负,因此鲍勃一定输。因此爱丽丝选1时会胜。当爱丽丝选择2时,N=N-2=2N=2时,先手的一定胜,故鲍勃一定会胜,因此爱丽丝负。故可知,N=4时,爱丽丝会获胜。以此类推即可。

参考代码

class Solution:
    def divisorGame(self, N: int) -> bool:
        n=[False,False,True,False]
        if N<4:
            return n[N]
        else:
            for i in range(4,N+1):
                ans=False
                for j in range(1,i):
                    if i%j==0:
                        ans=ans or (not n[i-j])
                n.append(ans)
            return n[N]

5030.节点与其祖先之间的最大差值

题目描述

给定二叉树的根节点 root,找出存在于不同节点 AB 之间的最大值 V,其中 V = |A.val - B.val|,且 AB 的祖先。(如果 A 的任何子节点之一为 B,或者 A 的任何子节点是 B 的祖先,那么我们认为 A 是 B 的祖先)

示例:
在这里插入图片描述

输入:[8,3,10,1,6,null,14,null,null,4,7,13]
输出:7
解释: 
我们有大量的节点与其祖先的差值,其中一些如下:
|8 - 3| = 5
|3 - 7| = 4
|8 - 1| = 7
|10 - 13| = 3
在所有可能的差值中,最大值 7 由 |8 - 1| = 7 得出。

提示:

  1. 树中的节点数在 25000 之间。
  2. 每个节点的值介于 0100000 之间。

解题思路

从根节点开始,同时遍历左子树和右子树。用两个变量记录之前层的最大值和最小值,返回这一层和之前的最大值最小值运算后的最大的差值,同时,更新到这一层为止的最大值和最小值,最终即可得到结果。

参考代码

/**
 * 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 work(TreeNode* root,int ma,int mi)
    {
        if(root==nullptr)return 0;
        int ans=max(ma-root->val,root->val-mi);
        ma=max(ma,root->val);
        mi=min(mi,root->val);
        ans=max(ans,max(work(root->left,ma,mi),work(root->right,ma,mi)));
        return ans;
    }
    int maxAncestorDiff(TreeNode* root) {
        return work(root,-100000,100000);
    }
};

5025.最长等差数列

题目描述

给定一个整数数组 A,返回 A 中最长等差子序列的长度
回想一下,A 的子序列是列表 A[i_1], A[i_2], ..., A[i_k] 其中 0 <= i_1 < i_2 < ... < i_k <= A.length - 1。并且如果 B[i+1] - B[i]( 0 <= i < B.length - 1) 的值都相同,那么序列 B 是等差的。
示例1:

输入:[3,6,9,12]
输出:4
解释: 
整个数组是公差为 3 的等差数列。

示例2:

输入:[9,4,7,2,10]
输出:3
解释:
最长的等差子序列是 [4,7,10]。

示例3:

输入:[20,1,15,3,10,5,8]
输出:4
解释:
最长的等差子序列是 [20,15,10,5]。

提示:

  1. 2 <= A.length <= 2000
  2. 0 <= A[i] <= 10000

解题思路

如果A的长度小于3,则直接返回A的长度。否则,默认初始长度为2,遍历A。对于每个数,计算其与后面数的公差,如果存在一个等差序列,则记录其长度。最后返回最长的序列即可。具体实现见参考代码。

参考代码

class Solution {
    public int longestArithSeqLength(int[] A) {
        int ALen = A.size();
        if (ALen < 3)
            return ALen;
        int maxLen = 2;
        for (int i = 0; i < ALen-1; i++) {
            for (int j = i+1; j < ALen; j++) {
                int diff = A[j] - A[i];
                int prev = A[j];
                int count = 2;
                for (int k = j+1; k < ALen; k++) {
                    if (A[k] == prev + diff){
                        count++;
                        prev += diff;
                    }
                }
                if (count > maxLen){
                    maxLen = count;
                }
            }
        }
        return maxLen;
    }
};

5031.从先序遍历还原二叉树

我们从二叉树的根节点 root 开始进行深度优先搜索。
在遍历中的每个节点处,我们输出 D 条短划线(其中 D 是该节点的深度),然后输出该节点的值。(如果节点的深度为 D,则其直接子节点的深度为 D + 1。根节点的深度为 0)。
如果节点只有一个子节点,那么保证该子节点为左子节点。
给出遍历输出 S,还原树并返回其根节点 root
示例1:
在这里插入图片描述

输入:"1-2--3--4-5--6--7"
输出:[1,2,5,3,4,6,7]

示例2:
在这里插入图片描述

输入:"1-2--3---4-5--6---7"
输出:[1,2,5,3,null,6,null,4,null,7]

示例3:
在这里插入图片描述

输入:"1-401--349---90--88"
输出:[1,401,null,349,88,90]

提示:

  • 原始树中的节点数介于 11000 之间。
  • 每个节点的值介于 110 ^ 9 之间。

解题思路

首先,解析字符串,获取每个节点的数值和深度。
随后由上至下,根据节点的深度建立树。
具体实现配合参考代码讲解

参考代码

/**
 * 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 a[1005]={0},d[1005];
    TreeNode* work(int l,int r)
    {
        if(l>r)return nullptr;
        TreeNode* root=new TreeNode(a[l]);
        if(l==r)return root;
        int mid;
        for(mid=l+2;mid<=r;mid++)if(d[mid]==d[l]+1)break;
        root->left=work(l+1,mid-1);
        root->right=work(mid,r);
        return root;
    }
    TreeNode* recoverFromPreorder(string S) {
        int i,j,m=S.size(),n;
        for(i=n=0;i<S.size();)
        {
            for(j=0;S[i]=='-';i++,j++);
            d[++n]=j;
            for(;i<S.size()&&S[i]>='0'&&S[i]<='9';i++)a[n]=(a[n]<<3)+(a[n]<<1)+(S[i]^'0');
        }
        return work(1,n);
    }
};

其中:

 int a[1005]={0},d[1005];

a用于记录节点的值,b用于记录节点的深度。
分析主函数:

TreeNode* recoverFromPreorder(string S) {
        int i,j,m=S.size(),n;
        for(i=n=0;i<S.size();)
        {
            for(j=0;S[i]=='-';i++,j++);
            d[++n]=j;
            for(;i<S.size()&&S[i]>='0'&&S[i]<='9';i++)
            	a[n]=(a[n]<<3)+(a[n]<<1)+(S[i]^'0');
        }
        return work(1,n);
    }

其中,n用于记录节点数目。
for循环用于解析字符串。如果遇到的是’-’,则j增加,当循环条件不满足时,记录节点的深度。
当遇到数字时,当前节点的值通过如下方式计算:

  • 先将a[n]上现有数字扩大十倍。这里扩大的方法是将一个数变为其八倍加其二倍,而八倍和二倍都可以通过左移运算进行。这样极大的提高了运算速度。
  • 随后,通过异或运算将字符串转换为数值。

接下来分析核心部分:

TreeNode* work(int l,int r)
    {
        if(l>r)return nullptr;
        TreeNode* root=new TreeNode(a[l]);
        if(l==r)return root;
        int mid;
        for(mid=l+2;mid<=r;mid++)if(d[mid]==d[l]+1)break;
        root->left=work(l+1,mid-1);
        root->right=work(mid,r);
        return root;
    }

其中的mid是判断下一层的下一层的起点。每次建立一个节点,随后递归建立其左子树和右子树。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值