Problem A - 找出3位偶数
题意
数组中任选三个数拼接成三位数,要求非偶数、无前导0,升序返回所有符合条件的数
思路
看到给定数组的范围是100,直接三重循环暴力搞定。由于要求不重复,用set处理了一下。
代码
class Solution {
public:
vector<int> findEvenNumbers(vector<int>& digits) {
int n=digits.size();
set<int> ans;
vector<int> res;
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
for(int k=0;k<n;k++){
if(i!=j&&i!=k&&j!=k){
int x=digits[i]*100+digits[j]*10+digits[k];
if(x>=100&&x%2==0) ans.insert(x);
}
}
}
}
for(auto i:ans) res.push_back(i);
return res;
}
};
Problem B - 删除链表的中间节点
题意:
给你一个链表的头节点 head 。删除链表的中间节点
思路:
先一次遍历求长度len
,然后再遍历跳过⌊len/2⌋
即可
代码
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
int getLength(ListNode* head) {
int length = 0;
while (head) {
++length;
head = head->next;
}
return length;
}
ListNode* deleteMiddle(ListNode* head) {
ListNode* dummy = new ListNode(0, head);
int len=getLength(head);
ListNode* cur = dummy;
for (int i = 0; i < len/2; ++i) cur = cur->next;
cur->next = cur->next->next;
ListNode* ans = dummy->next;
delete dummy;
return ans;
}
};
Problem C - 从二叉树一个节点到另一个节点每一步的方向
题意:
给定二叉树,求起点到终点的路径(向上是U,左是L,右是R)。
思路:
首先,我们很容易想到最近公共祖先(LCA),那么结合计算树上两点距离时用的技巧(到根节点距离之和-2*(LCA到根的距离)),我们能够想到:
- 分别计算根节点到起点与终点的路径(dfs)
- 去掉两个路径的公共前缀(到LCA的路径),得到LCA分别到起点、终点的路径
- 求str1: 起点跑向LCA的过程,全部换成’U’
- 求str2: LCA跑向终点的过程,就是
根节点到终点的路径-根节点到LCA的路径
,上面去掉前缀后就不需要处理了
于是上面的str1+str2即为答案
代码
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
string st="",ed="",tmp="";
void dfs(TreeNode* now,int to1,int to2){
if(now==nullptr) return;
if(now->val==to1) st=tmp;
if(now->val==to2) ed=tmp;
if(now->left!=nullptr){
tmp+="L";
dfs(now->left,to1,to2);
tmp.pop_back();
}
if(now->right!=nullptr){
tmp+="R";
dfs(now->right,to1,to2);
tmp.pop_back();
}
}
string getDirections(TreeNode* root, int startValue, int destValue) {
if(root==nullptr) return tmp;
dfs(root,startValue,destValue);
int ind=0;
while(ind<min(st.size(),ed.size())&&st[ind]==ed[ind]) ind++;
string ans;
for(int i=ind;i<st.size();i++) ans+="U";
for(int i=ind;i<ed.size();i++) ans+=ed[i];
return ans;
}
};
Problem D - 合法重新排列数对
题意
给你n个二元组,重新排列以使得:每一个二元组的第二个元素等于下一个二元组的第一个元素
思路
我们将每个二元组[u,v]
视作u到v的一条有向边,则本题转化为经典有向图欧拉路径。由于保证有解,题目给定的图一定满足以下二者之一:
- 所有点入度等于出度;
- 恰有一个点出度 = 入度 + 1(欧拉路径的起点),且恰有一个点入度 = 出度 + 1(欧拉路径的终点),其他点入度等于出度。
即本题对应图必然为欧拉/半欧拉图。对于第一种,任意选择一点开始 dfs 即可;对于第二种则选择起点开始dfs。复杂度
O
(
m
)
\mathcal{O}(m)
O(m)。
注意处理时通过从后面删边的方法来降低复杂度,因为这样做可以使得每一条边只访问一次,从而达到
O
(
m
)
\mathcal{O}(m)
O(m)的复杂度。
代码
class Solution {
map<int, vector<int>> mp;
map<int, int> deg;
vector<vector<int>> ans;
void dfs(int sn) {
vector<int> &e = mp[sn];
while (!e.empty()) {
int fn = e.back();
e.pop_back();
dfs(fn);
ans.push_back(vector<int>{sn, fn});
}
}
public:
vector<vector<int>> validArrangement(vector<vector<int>>& pairs) {
for (auto &pair : pairs) {
mp[pair[0]].push_back(pair[1]);
deg[pair[0]]--, deg[pair[1]]++;
}
for (auto i:deg) if (i.second == -1) dfs(i.first);
if (ans.empty()) dfs(deg.begin()->first);
reverse(ans.begin(), ans.end());
return ans;
}
};