leetcode 19 重新安排行程

0. 难点

  1. 一个行程中,如果航班处理不好容易变成一个圈,成为死循环
  2. 有多种解法,字母序靠前排在前面,让很多同学望而退步,如何该记录映射关系呢 ?
  3. 使用回溯法(也可以说深搜) 的话,那么终止条件是什么呢?
  4. 搜索的过程中,如何遍历一个机场所对应的所有机场。

1. 初次写40min,没有什么方法论…

一开始选的数据结构不好,后面就直接陷进去了。直接按照常规的邻接表写了一个unordered_map<string, vector<string>>

对难点的处理:

  1. 一个行程中,如果航班处理不好容易变成一个圈,成为死循环。
    1. 进入递归的时候,把已经选过的航班删除了!后面在恢复。一层回溯就 o ( n 2 ) o(n^2) o(n2)
  2. 有多种解法,字母序靠前排在前面,让很多同学望而退步,如何该记录映射关系呢 ?
    1. 我直接在记录完的时候对unordered_map<string, vector<string>>中的邻接表vector<string>排序一下。o(n^2 * logn)
  3. 使用回溯法(也可以说深搜) 的话,那么终止条件是什么呢?
    1. 正确处理,path的size是机票的size+1。
  4. 搜索的过程中,如何遍历一个机场所对应的所有机场。
    1. 在我的数据结构之下,遍历vector<string>并不会困难,难点在于增删元素,和对迭代器的处理。

对于难点1:c++ primer学了总得应用一下,边遍历数组还边删元素又不是不可行,在这调了一会,果然成了,最后超时了(通过样例80/81),发现忘记erase和insert是o(n)复杂度的了。这样一层递归就直接o(n2)了,递归还会最坏在外面套一层o(n2)(在完全图的情况下。)

        for(auto itAdj=adjs.begin();itAdj!=adjs.end();itAdj++)
        {
            string adj = *itAdj;
            // cout<<adj<<endl;
            path.emplace_back(adj); 
            itAdj = adjs.erase(itAdj); // 迭代器删了会默认指向下一个元素
            // cout<<"剩余选择:{";
            // for(auto val:adjs) cout<<val<<" "; cout<<"}"<<endl;
            dfs(adj);
            if(findRet) return;
            path.pop_back();
            itAdj = adjs.insert(itAdj,adj); // 插入回来之后,迭代器指向插入的元素,说明实际上恢复如初了。
        }

所以要选择一个1. 有序 2. 容易增删元素,迭代器不会失效。
unordered_map<string, map<string,int>>;

在遍历的时候,每层循环只需要
for(auto& [k,v]:map) // o(n)

2. 最终代码

class Solution {
public:
    vector<string> path{"JFK"};
    unordered_map<string, map<string, int>> m;
    size_t retSize;
    bool findRet = false;
    vector<string> findItinerary(vector<vector<string>>& tickets) {
        for(auto& vs:tickets)
        {
            m[vs[0]][vs[1]] += 1;
        }
        retSize = tickets.size()+1;
        dfs("JFK");
        return path;
    }

    bool dfs(string start)
    {
        if(path.size() == retSize)
        {
            return true;
        }

        for(auto& [dst, cnt]:m[start])
        {
            if(cnt > 0)
            {
                cnt--;
                path.emplace_back(dst);
                if(dfs(dst)) return true;
                path.pop_back();
                cnt++;
            }
        }
        return false;
    }
};
  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值