【代码随想录】刷题Day30

文章介绍了两个编程问题的解决方法,一个是括号生成,利用递归和回溯策略生成所有可能的合法括号组合;另一个是航班路径的重新安排,通过unordered_map存储飞机场之间的航线信息,并使用回溯搜索找到最长的飞行路径。
摘要由CSDN通过智能技术生成

1.括号生成

22. 括号生成

其实不考虑减枝,下面代码就是将所有开头第一个括号为“(”的结果一并写出了

s+='(';
_generateParenthesisR(ret,s,left+1,right,n);
s.pop_back();
s+=')';
_generateParenthesisR(ret,s,left,right+1,n);
s.pop_back();

那么此外我们就要进行减枝和收获的判断

1.首先明确每一个参数是干什么的:

vector<string>& ret存放收获的返回结果

string& s存每次递归的结果

int left,int right,分别用于记录左右括号的出现次数

int& n,为题目给出的几组括号

2.那么我们的判断条件其实很简单:要清楚我们是先考虑左括号的

那么条件就有以下三种:收获的情况 / 不可出现的情况 / 左括号满的情况

left==n&&right==n:此时都是成双成对,那么我们收获即可

left<right:结果右括号的数大于左括号的数,那么这个结果是错误的,直接返回给上层

eft==n&&right<n:左括号满了,那么此时只能操作右括号

class Solution {
public:
    void _generateParenthesisR(vector<string>& ret,string& s,int left,int right,int& n)
    {
        if(left==n&&right==n)
        {
            ret.push_back(s);
            return;
        }
        else if(left<right)
        {
            return;
        }
        else if(left==n&&right<n)
        {
            s+=')';
            _generateParenthesisR(ret,s,left,right+1,n);
            s.pop_back();
            return;
        }
        s+='(';
        _generateParenthesisR(ret,s,left+1,right,n);
        s.pop_back();
        s+=')';
        _generateParenthesisR(ret,s,left,right+1,n);
        s.pop_back();
    }

    vector<string> generateParenthesis(int n) {
        vector<string> ret;
        string s;
        _generateParenthesisR(ret,s,0,0,n);
        return ret;
    }
};

2.重新安排行程

332. 重新安排行程

本题最难的地方有两处:1.怎么表示各点关系 2.怎么用代码遍历

其实思路和之前的回溯都差不多,最难的点搞定后无非就是回溯暴力求解

1.怎么表示各点关系:使用unordered_map<string, map<string, int>> targets定义,第一个string为以该点出发的飞机场名;map的string是表示能去往哪里的飞机场名;map的int是标明在递归时,我们是否已经去过这条路了。

2.介绍函数的参数

ret:返回结果的容器

targets:所有飞机场路线的图,需要遍历的到;思路就是遍历tickets,对应的左边是第一个string,右边是第二个string,我们要做的就是将第二个string的int类型记录加一,表示左边的飞机场到右边的飞机场有一个路径,全部遍历。

for (auto& e : tickets)
    targets[e[0]][e[1]]++;

num:当前层的飞机已走路径数量

3.

* 遍历条件其实很简单了,我们只需要找到唯一的那条最长路(起点加上所有路径之和的数量就是我们所想要的最后终止条件),所以我们的函数返回值为bool,只需要返回最终结果即可,最终为ret.size() == num

* 那么auto& e : targets[ret[ret.size() - 1]]找到当前飞机场能走向的其他飞机场情况,如果有则second--,ret要push当前的飞机场,随后进行回溯。如果回溯的结果成功,说明其他结果没必要,直接向上返回true。那回溯的思路就是ret先pop最后的飞机场,secong重新++回来

class Solution {
public:
    bool backtrace(vector<string>& ret, unordered_map<string, map<string, int>>& targets, int& num)
    {
        if (ret.size() == num)
            return true;
        //写法一
        /*for(auto& it:targets)
        {
            cout<<it.first<<" "<<ret[ret.size() - 1]<<endl;
            if(it.first==ret[ret.size() - 1])
            {
                for(auto& e: it.second)
                {
                    if (e.second > 0)
                    {
                        ret.push_back(e.first);
                        e.second--;
                        if (backtrace(ret, targets, num))
                            return true;
                        ret.pop_back();
                        e.second++;
                    }
                }
            }
        }*/
        //写法二
        for (auto& e : targets[ret[ret.size() - 1]])
        {
            if (e.second > 0)
            {
                ret.push_back(e.first);
                e.second--;
                if (backtrace(ret, targets, num))
                    return true;
                ret.pop_back();
                e.second++;
            }
        }
        return false;
    }
    vector<string> findItinerary(vector<vector<string>>& tickets) {
        vector<string> ret;
        unordered_map<string, map<string, int>> targets;
        targets.clear();
        for (auto& e : tickets)
            targets[e[0]][e[1]]++;
        ret.push_back("JFK");
        int num = tickets.size() + 1;
        backtrace(ret, targets, num);
        return ret;
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

灼榆

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值