LeetCode 169周赛

本文回顾了LeetCode 169周赛的四道题目,重点讨论了使用DFS和回溯算法的解题策略。在A题中,通过简单的对称输出得到答案;B题提供了两种解法,包括排序和合并有序数组;C题采用BFS解决跳跃游戏问题;D题是口算难题,用回溯算法求解。作者在总结中反思了自己在DFS上的不足,并建议在面对复杂问题时考虑其他方法。
摘要由CSDN通过智能技术生成

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] iarr[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: 口算难题

题目大意:
你需要根据以下规则检查方程是否可解:

  1. 每个字符都会被解码成一位数字( 0 − 9 0 - 9 09)。
  2. 每对不同的字符必须映射到不同的数字。
  3. 每个 w o r d s [ i ] words[i] words[i] r e s u l t result result 都会被解码成一个没有前导零的数字。
  4. 左侧数字之和( 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. 注意两点。

  1. 首位不能为0.
  2. 找到结果后立即退出回溯。
  3. 注意回溯顺序。

代码展示:(国服第一(坑某人)的代码,太美了吧!!!)

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);
    }
};

总结

弱鸡还是看论文吧!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值