LeetCode2019第169场周赛

1304. 和为零的N个唯一整数

题目描述

给你一个整数 n,请你返回 任意 一个由 n 个 各不相同 的整数组成的数组,并且这 n 个数相加和为 0 。 示例 1: 输入:n = 5 输出:[-7,-1,1,3,4] 解释:这些数组也是正确的 [-5,-1,1,2,3],[-3,-1,2,-2,4]。 示例 2: 输入:n = 3 输出:[-1,0,1] 示例 3: 输入:n = 1 输出:[0] 提示: 1 <= n <= 1000

题解1

产生n个不同的数字和为0的方式有很多种,可以对称产生0左右两边的数。具体 如果$n = 2 m$,则结果为:$-m, -(m - 1), \dots, -1, 1, \dots, m - 1, m$。 如果$n = 2 m + 1$,则结果为:$-m, -(m - 1), \dots, -1, 0,1, \dots, m - 1, m$。

代码1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Solution {
public:
vector<int> sumZero(int n) {
vector<int>res;
if(n & 1 == 1){
res.push_back(0);
}
for(int i = 1; i <= n >> 1; ++i){
res.push_back(i);
res.push_back(-i);
}
return res;
}
};

1305. 两棵二叉搜索树中的所有元素

题目描述

给你 root1 和 root2 这两棵二叉搜索树。 请你返回一个列表,其中包含 两棵树 中的所有整数并按 升序 排序。. 示例 1: 输入:root1 = [2,1,4], root2 = [1,0,3] 输出:[0,1,1,2,3,4] 示例 2: 输入:root1 = [0,-10,10], root2 = [5,1,7,0,2] 输出:[-10,0,0,1,2,5,7,10] 示例 3: 输入:root1 = [], root2 = [5,1,7,0,2] 输出:[0,1,2,5,7] 示例 4: 输入:root1 = [0,-10,10], root2 = [] 输出:[-10,0,10] 示例 5: 输入:root1 = [1,null,8], root2 = [8,1] 输出:[1,1,8,8] 提示: 每棵树最多有 5000 个节点。 每个节点的值在 [-10^5, 10^5] 之间。

题解1

对于二叉搜索树,中序遍历可以得到有序的序列。分别对两棵二叉搜索树中序遍历,然后再对结果进行归并排序。 但比赛为了求速度,直接将结果用sort排序。

代码1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/

void inorder(TreeNode* root, vector<int>& res){
if(root == NULL){
return;
}
inorder(root->left, res);
res.push_back(root->val);
inorder(root->right, res);
}
class Solution {
public:
vector<int> getAllElements(TreeNode* root1, TreeNode* root2) {
vector<int>res1;
inorder(root1, res1);//中序遍历
inorder(root2, res1);//中序遍历
sort(res1.begin(), res1.end());//这里可修改为归并排序
return res1;
}
};

1306. 跳跃游戏 III

题目描述

这里有一个非负整数数组 arr,你最开始位于该数组的起始下标 start 处。当你位于下标 i 处时,你可以跳到 i + arr[i] 或者 i - arr[i]。 请你判断自己是否能够跳到对应元素值为 0 的 任意 下标处。 注意,不管是什么情况下,你都无法跳到数组之外。 示例 1: 输入:arr = [4,2,3,0,3,1,2], start = 5 输出:true 解释: 到达值为 0 的下标 3 有以下可能方案: 下标 5 -> 下标 4 -> 下标 1 -> 下标 3 下标 5 -> 下标 6 -> 下标 4 -> 下标 1 -> 下标 3 示例 2: 输入:arr = [4,2,3,0,3,1,2], start = 0 输出:true 解释: 到达值为 0 的下标 3 有以下可能方案: 下标 0 -> 下标 4 -> 下标 1 -> 下标 3 示例 3 输入:arr = [3,0,2,1,2], start = 2 输出:false 解释:无法到达值为 0 的下标 1 处。 提示: 1 <= arr.length <= 5 * 10^4 0 <= arr[i] < arr.length 0 <= start < arr.length

题解1

BFS,判断能否从起始下标到达值为0的下标位置

代码1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
class Solution {
public:
bool canReach(vector<int>& arr, int start) {
vector<int>target;
int len = arr.size(), frt;
bool flag = false, res = false;
vector<int>mark(len, 0);
vector<int>mark1(len, 0);
for(int i = 0; i < arr.size(); ++i){//将值为0的数字的下标进行标记
if(arr[i] == 0){
mark[i] = 1;
flag = true;
}
}
if(!flag){//不存在值为0的数字
res = false;
}
else{
//BFS
queue<int>que;
que.push(start);
mark1[start] = 1;
while(!que.empty()){
frt = que.front();
que.pop();
if(mark[frt]){//移动值为0的位置,直接break
res = true;
break;
}
if(frt + arr[frt] < len && !mark1[frt + arr[frt]]){//向前移
que.push(frt + arr[frt]);
mark1[frt + arr[frt]] = 1;
}
if(frt - arr[frt] >= 0 && !mark1[frt - arr[frt]]){//向后移
que.push(frt - arr[frt]);
mark1[frt - arr[frt]] = 1;
}
}
}
return res;
}
};

1307. 口算难题

题目描述

给你一个方程,左边用 words 表示,右边用 result 表示。 你需要根据以下规则检查方程是否可解: 每个字符都会被解码成一位数字(0 - 9)。 每对不同的字符必须映射到不同的数字。 每个 words[i] 和 result 都会被解码成一个没有前导零的数字。 左侧数字之和(words)等于右侧数字(result)。 如果方程可解,返回 True,否则返回 False。 示例 1: 输入:words = [“SEND”,”MORE”], result = “MONEY” 输出:true 解释:映射 ‘S’-> 9, ‘E’->5, ‘N’->6, ‘D’->7, ‘M’->1, ‘O’->0, ‘R’->8, ‘Y’->’2’ 所以 “SEND” + “MORE” = “MONEY” , 9567 + 1085 = 10652 示例 2: 输入:words = [“SIX”,”SEVEN”,”SEVEN”], result = “TWENTY” 输出:true 解释:映射 ‘S’-> 6, ‘I’->5, ‘X’->0, ‘E’->8, ‘V’->7, ‘N’->2, ‘T’->1, ‘W’->’3’, ‘Y’->4 所以 “SIX” + “SEVEN” + “SEVEN” = “TWENTY” , 650 + 68782 + 68782 = 138214 示例 3: 输入:words = [“THIS”,”IS”,”TOO”], result = “FUNNY” 输出:true 示例 4: 输入:words = [“LEET”,”CODE”], result = “POINT” 输出:false 提示: 2 <= words.length <= 5 1 <= words[i].length, results.length <= 7 words[i], result 只含有大写英文字母 表达式中使用的不同字符数最大为 10

题解1

因为表达式中使用的不同字符数最大为10,字符的取值0-9(值不能相同)最多为$10!$种情况。思路如下: 首先将不重复的字符统计出来,然后用next_permutation产生不同的取值,判断是否符合情况。 这种暴力方式会超时,因为next_permutation产生取值的时间需要o(n)时间,并且包含重复的情况。

代码1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
//超时
bool deal(vector<string>& words, string& result, unordered_map<char, int>& myMap){
for(int i = 0; i < words.size(); ++i){
if(words[i].size() > 1 && myMap[words[i][0]] == 0){//前导0
return false;
}
}
if(result.size() > 1 && myMap[result[0]] == 0){//前导0
return false;
}
int lSum = 0, rSum = 0, num = 0;
for(auto word:words){
num = 0;
for(auto ch:word){
num = num * 10 + myMap[ch];
}
lSum += num;
}
for(auto ch:result){
rSum = rSum * 10 + myMap[ch];
}
return lSum == rSum;
}
class Solution {
public:
bool isSolvable(vector<string>& words, string result) {
int len;
unordered_map<char, int>myMap;
string str;
int flag = false;
int arr[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
for(auto word:words){
for(auto ch:word){
if(myMap.find(ch) == myMap.end()){
str.push_back(ch);
myMap[ch] = 0;
}
}
}
len = str.size();
do{
for(int i = 0; i < len; ++i){
myMap[str[i]] = arr[i];
}
if(deal(words, result, myMap)){
flag = true;
break;
}
}while(next_permutation(arr, arr + 10));
return flag;
}
};

题解2

用dfs来代替next_permutation,不会产生重复的情况。加入前导0的标记并将map换成数组。

代码2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
vector<int>myMap(26, 0);
vector<bool>mark(26, 0);
string str;
bool res = false;

bool deal(vector<string>& words, string& result){//判断相加后是否相等
int lSum = 0, rSum = 0, num = 0;
for(auto word:words){
num = 0;
for(auto ch:word){
num = num * 10 + myMap[ch - 'A'];
}
lSum += num;
}
for(auto ch:result){
rSum = rSum * 10 + myMap[ch - 'A'];
}
return lSum == rSum;
}

void dfs(vector<string>& words, string& result, int pos, int used){//递归暴力
if(res){
return;
}
if(pos == str.size()){
if(deal(words, result)){
res = true;
}
return;
}
for(int i = 0; i < 10; ++i){
if((mark[str[pos] - 'A'] && i == 0) used >> i & 1) continue;//前导0或者数字重复
myMap[str[pos] - 'A'] = i;
dfs(words, result, pos + 1, used 1 << i);
}

}


class Solution {
public:
bool isSolvable(vector<string>& words, string result) {
int len;
myMap.clear();
str.clear();
res = false;
mark.assign(26, 0);
myMap.assign(26, 0);
for(auto word:words){//统计字符的个数
mark[word[0] - 'A'] = 1;
for(auto ch:word){
if(!myMap[ch - 'A']){
str.push_back(ch);
myMap[ch - 'A'] = 1;
}
}
}
mark[result[0] - 'A'] = 1;
for(auto ch:result){
if(!myMap[ch - 'A']){
str.push_back(ch);
myMap[ch - 'A'] = 1;
}
}
len = str.size();
dfs(words, result, 0, 0);
return res;
}
};

题解3

参照圈子

代码3

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
vector<char> h;
vector<int> base;
vector<int> coe(26,0);
vector<bool> not_zero(26,false);

bool dfs (int pos,int used, int sum) {
if(pos == h.size()) return sum == 0;
for(int i = 0 ; i < 10 ; i++) {
if(used>>i & 1) continue;
if(i==0 && not_zero[h[pos]-'A']) continue;
if(dfs(pos+1,used 1<<i, sum+i*coe[h[pos]-'A'])) return true;
}
return false;
};


class Solution {
public:
bool isSolvable(vector<string>& words, string result) {

h.clear();
base.clear();
coe.assign(26, 0);
not_zero.assign(26, false);
words.push_back(result);
base.push_back(1);
for(int i = 1 ; i <= 8 ; i++) base.push_back(base.back()*10);

for(int j = 0 ; j < words.size() ; j++) {
string x = words[j];
for(int i = 0 ; i < x.size() ; i++) {
if(i==0) not_zero[x[i]-'A'] = true;
h.push_back(x[i]);
int flag = j==words.size()-1?-1:1;
coe[x[i]-'A'] += flag * base[x.size()-1-i];
}
}
sort(h.begin(),h.end());
h.erase(unique(h.begin(),h.end()),h.end());
return dfs(0,0,0);
}
};