Alice and Bob take turns playing a game, with Alice starting first.
Initially, there is a number N on the chalkboard. On each player’s turn, that player makes a move consisting of:
Choosing any x with 0 < x < N and N % x == 0.
Replacing the number N on the chalkboard with N - x.
Also, if a player cannot make a move, they lose the game.
Return True if and only if Alice wins the game, assuming both players play optimally.
Example 1:
Input: 2
Output: true
Explanation: Alice chooses 1, and Bob has no more moves.
Example 2:
Input: 3
Output: false
Explanation: Alice chooses 1, Bob chooses 1, and Alice has no more moves.
给定一个整数N,A先手,每次A和B可以从N的因子中移走一个数0<x<N,使N变为N-x,最后无法移动时为输
这道题刚开始做的时候举了几个例子:
N=1 lose
N=2 win
N=3 lose
N=4 win
···
于是有个直觉,直接判断奇偶即可,结果一试还真是… 真不愧是easy难度
然后比赛结束后想了想原因,解释如下:
- 假设对于数字N,A必输,那么对于数字N+1,A必赢,因为A可以先手移1,使N+1变为N,这样B必输
- 而对于任意奇数N,由于N的因子中必定不含有偶数,因此移动一次后,N将变为偶数
基于上述两条规律,来看一下:
当N=2,A必赢
N=3,A移动一次后,N将变为偶数,而比N小的偶数只有2,因此B必赢
N=4,由于N=3时A输,因此N=4,A赢
N=5,同理A移动一次后,N将变为偶数,而比N小的偶数有2和4,这两者都是B必赢
N=6,由于N=5时A输,因此N=6,A赢
于是可以得到,N为偶数必赢,奇数必输,代码:
class Solution {
public:
bool divisorGame(int N) {
return (N % 2 == 0);
}
};
1026. Maximum Difference Between Node and Ancestor
Given the root of a binary tree, find the maximum value V for which there exists different nodes A and B where V = |A.val - B.val| and A is an ancestor of B.
(A node A is an ancestor of B if either: any child of A is equal to B, or any child of A is an ancestor of B.)
Example 1:
Input: [8,3,10,1,6,null,14,null,null,4,7,13]
Output: 7
Explanation:
We have various ancestor-node differences, some of which are given below :
|8 - 3| = 5
|3 - 7| = 4
|8 - 1| = 7
|10 - 13| = 3
Among all possible differences, the maximum value of 7 is obtained by |8 - 1| = 7.
给定一棵二叉树,求出所有父节点与子节点之间最大的差值(绝对值)
遍历整棵树的同时,保留最大值和最小值即可,每次判断是否更新最大差值:
/**
* 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 maxAncestorDiff(TreeNode* root) {
if(root == NULL) return 0;
int maxn = 0;
// 初始化最大最小值均为根节点值
helper(root, root->val, root->val, maxn);
return maxn;
}
void helper(TreeNode* root, int maxn, int minn, int& res)
{
if(root == NULL) return;
int v = root->val;
res = max(res, max(abs(maxn-v), abs(minn-v)));
helper(root->left, max(maxn, v), min(minn, v), res);
helper(root->right, max(maxn, v), min(minn, v), res);
}
};
1027. Longest Arithmetic Sequence
Given an array A of integers, return the length of the longest arithmetic subsequence in A.
Recall that a subsequence of A is a list A[i_1], A[i_2], …, A[i_k] with 0 <= i_1 < i_2 < … < i_k <= A.length - 1, and that a sequence B is arithmetic if B[i+1] - B[i] are all the same value (for 0 <= i < B.length - 1).
Example 1:
Input: [3,6,9,12]
Output: 4
Explanation:
The whole array is an arithmetic sequence with steps of length = 3.
Example 2:
Input: [9,4,7,2,10]
Output: 3
Explanation:
The longest arithmetic subsequence is [4,7,10].
Example 3:
Input: [20,1,15,3,10,5,8]
Output: 4
Explanation:
The longest arithmetic subsequence is [20,15,10,5].
给定一个数组A,求出最长的Arithmetic Sequence
定义为:对于A[i], A[j], A[k]…,有:A[j]-A[i] = A[k]-A[j]
直接动态规划,dp[i][diff]表示到i为止,差值为diff的子串长度(-1),O(n2)复杂度
class Solution {
public:
int longestArithSeqLength(vector<int>& A) {
if (A.size() < 2) return 0;
int len = A.size();
map<int, map<int, int>> mm;
int maxn = 0;
for(int i = 0; i < len; ++i)
{
for(int j = 0; j < i; ++j)
{
int diff = A[i] - A[j];
mm[i][diff] = mm[j][diff] + 1;
maxn = max(maxn, mm[i][diff]);
}
}
return maxn + 1;
}
};
1028. Recover a Tree From Preorder Traversal
We run a preorder depth first search on the root of a binary tree.
At each node in this traversal, we output D dashes (where D is the depth of this node), then we output the value of this node. (If the depth of a node is D, the depth of its immediate child is D+1. The depth of the root node is 0.)
If a node has only one child, that child is guaranteed to be the left child.
Given the output S of this traversal, recover the tree and return its root.
Example 1:
Input: “1-2–3--4-5–6--7”
Output: [1,2,5,3,4,6,7]
Example 2:
Input: “1-2–3—4-5–6—7”
Output: [1,2,5,3,null,6,null,4,null,7]
给定一个字符串,为某二叉树的前序遍历结果,重构该二叉树
字符串中的’-‘表示该数字对应的深度
"1-2–3--4-5–6--7"为例
根节点深度为0
2前面有一个’-’,因此2深度为1
6前面有两个’-’, 则6深度为2
由于刷题不久,刚开始想用哈希表存每个深度对应的数字,但结果总有差异,后来看了赛后的解析,get了一个新技能,可以用stack来解,先上自己的代码:
/**
* 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* recoverFromPreorder(string S) {
stack<TreeNode*> st;
for (int i = 0; i < S.length();)
{
int depth = 0, num = 0;
// 求深度
while (S[i] == '-') depth++, i++;
// 求数字
while (i < S.length() && S[i] != '-')
{
num = num * 10 + S[i] - 48;
i++;
}
TreeNode* cur = new TreeNode(num);
while (st.size() > depth) st.pop();
if (!st.empty())
{
// left child is occupied
if (st.top()->left)
{
st.top()->right = cur;
}
else st.top()->left = cur;
}
st.emplace(cur);
}
while (st.size() > 1) st.pop();
return st.top();
}
};
前面一部分就不说了,分别求数字及其对应的深度,并创建当前树节点
由于字符串是前序遍历的结果,因此可以保证一定是左子树优先于右子树,因此每次push(代码中用的emplace函数,同样的效果,更高效)之前,保证当前的节点被push到指定的size(while (st.size() > depth) st.pop();
)
以"1-401–349—90–88"为例:
先创建根节点1
然后401节点,深度为1,小于等于当前stack的大小=1,又由于根节点左子树为空,则令其左子树为401
接下来349、90也是同理,一直push到左子树
当来到88时,此时stack大小为4,但88的深度为2,因此需要把349和90都pop出去(后进先出),此时stack中只剩下根节点1和其左子树401,发现左子树被占,自然而然88成为根节点的右子树
遍历结束,由于要返回根节点,此时stack中保存了根节点和其左右子树,因此要把左右子树都pop出去,最后返回根节点即可。