Leetcode 第270场周赛题解

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到根的距离)),我们能够想到:

  1. 分别计算根节点到起点与终点的路径(dfs)
  2. 去掉两个路径的公共前缀(到LCA的路径),得到LCA分别到起点、终点的路径
  3. 求str1: 起点跑向LCA的过程,全部换成’U’
  4. 求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;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值