Leetcode 169周赛
DFS关了,没剪枝,疯狂TLE
难顶啊!!!11点才开始做的,第四题一看数据这么少,铁暴力做啊!写完就TLE了,然后,就没有然后了,12点到了,真是弱鸡啊!先挂前三道题答案吧!
A: 和为零的N个唯一整数
题目大意:
给定整数n,返回n个不同整数组成的数组,要求和为0;
解题思路:
围绕0对称输出即可。送分题
代码展示:
class Solution {
public:
vector<int> sumZero(int n) {
vector<int> ans;
if(n%2){
ans.push_back(0);
for(int i=1;i<=n/2;i++) ans.push_back(i),ans.push_back(-i);
}else
for(int i=1;i<=n/2;i++) ans.push_back(i),ans.push_back(-i);
return ans;
}
};
B: 两棵二叉搜索树中的所有元素
题目大意:
给定两棵二叉搜索树,返回包含两棵树所有整数的升序列表。
解题思路:
解法一:简单思路,遍历两棵二叉树,然后排序,时间复杂度
O
(
(
n
+
m
)
l
o
g
(
n
+
m
)
)
O((n+m)log(n+m))
O((n+m)log(n+m))。
解法二:中序遍历两棵二叉树,合并两个有序数组,时间复杂度
O
(
m
+
n
)
O(m+n)
O(m+n)。
代码展示:
/**
* 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:
vector<int> ans;
void add(TreeNode* root){
if(root==NULL) return;
ans.push_back(root->val);
add(root->left);
add(root->right);
}
vector<int> getAllElements(TreeNode* root1, TreeNode* root2) {
add(root1);add(root2);
sort(ans.begin(),ans.end());
return ans;
}
};
C: 跳跃游戏 III
题目大意:
给定arr数组,起始位置start,位于i的时候,你可以跳到
i
+
a
r
r
[
i
]
i+arr[i]
i+arr[i]或者
i
−
a
r
r
[
i
]
i-arr[i]
i−arr[i]。为是否跳到为0的位置。
解题思路:
简单BFS,每次两种情况。知道遍历完看是否存在一个点0且在BFS过程访问即可。
杀某逆向思维解了一波,从0的位置,反向找能跳到当前位置的点,看是否有start即可。
代码展示:
class Solution {
public:
int vis[50001];
bool canReach(vector<int>& arr, int start) {
memset(vis,0,sizeof vis);
int n=arr.size();
vector<int> pos;
for(int i=0;i<n;i++) if(arr[i]==0){
pos.push_back(i);
vis[i]=1;
}
int t=0;
while(1){
for(int i:pos) if(i==start) return true;
int flag=1,m=pos.size();
for(int i=t;i<m;i++) //这里注意pos大小一直再变喔
for(int j=0;j<n;j++)
if(!vis[j] && ((j+arr[j]<n && j+arr[j]==pos[i]) || (j-arr[j]>=0 && j-arr[j]==pos[i]))){
pos.push_back(j);
vis[j]=1;
flag=0;
}
if(flag) return false;
t=m;
}
}
};
D: 口算难题
题目大意:
你需要根据以下规则检查方程是否可解:
- 每个字符都会被解码成一位数字( 0 − 9 0 - 9 0−9)。
- 每对不同的字符必须映射到不同的数字。
- 每个 w o r d s [ i ] words[i] words[i] 和 r e s u l t result result 都会被解码成一个没有前导零的数字。
- 左侧数字之和( w o r d s words words)等于右侧数字( r e s u l t result result)。
如果方程可解,返回 True,否则返回 False。
解题思路:
典型的回溯算法。 理论上时间复杂度为
O
(
10
!
∗
k
)
O(10! * k)
O(10!∗k), 其中k为每次计算的常数因子, 约等于
Σ
∣
w
o
r
d
s
i
∣
+
∣
r
e
s
u
l
t
∣
\Sigma |words_i| + |result|
Σ∣wordsi∣+∣result∣. 注意两点。
- 首位不能为0.
- 找到结果后立即退出回溯。
- 注意回溯顺序。
代码展示:(国服第一(坑某人)的代码,太美了吧!!!)
class Solution{
public:
bool canZero[26];
int left[15],right[15],numc;
map<char, int> toIndex;
bool vis[15];
void calcWeight(const string &s, int arr[]){
int n=s.size(),w=1;
for(int i=n-1;i>=0;i--){
arr[toIndex[s[i]]] += w;
w*=10;
}
}
bool dfs(int cur, int n, int l, int r){
if(cur>n){
if(l==r) cout<<l<<endl;
return l==r;
}
for(int i=0;i<=9;i++){
if(!canZero[cur] && i==0) continue;
if(vis[i]) continue;
vis[i]=true;
bool flag = dfs(cur+1, n,l+i*left[cur],r+i*right[cur]);
if(flag) return true;
vis[i]=false;
}
return false;
}
bool isSolvable(vector<string>& words, string result){
numc=0;toIndex.clear();
for(auto &w:words) for(auto c:w){
if(toIndex[c]==0) toIndex[c]=++numc;
}
for(auto c:result){
if(toIndex[c]==0) toIndex[c] = ++numc;
}
for(int i=0;i<26;i++) canZero[i]=true;
canZero[toIndex[result[0]]]=false;
for(auto &w:words) canZero[toIndex[w[0]]]=false;
memset(left,0,sizeof left);
memset(right,0,sizeof right);
calcWeight(result, right);
for(auto &w: words) calcWeight(w, left);
memset(vis,false,sizeof vis);
return dfs(1,numc,0,0);
}
};
总结
弱鸡还是看论文吧!