day30 重新安排行程 N皇后 解数独

题目1:332 重新安排行程

题目链接:332 重新安排行程

题意

机票列表数组tickets  tickets[i=[fromi,toi]表示飞机出发和降落的地点  重新安排行程

机票都从JFK机场出发  按字典排序返回最小的行程组合  例如:["JFK",''LGA'']比["JFK",''LGB'']小,排序更靠前  机场都用大写字母表示

所有机票必须使用且只能使用1次

步骤

1)记录映射关系(字母序靠前的机场排在前面  一个出发机场对应多个到达机场,使用unordered_map结构做映射 ;这多个到达机场要有顺序,使用map做映射)

例如:["JFK",''LGA'']和["JFK",''LGB'']  JFK作为出发机场 对应的到达机场有2个(LGA,LGB),需要对这2个到达机场按照字母的顺序进行排序  ,JFK->LGA LGB  LGA靠前,LGB在LGA后面

由于出发机场和到达机场会重复,所以搜索过程要及时删除该机场,防止出现死循环,如图(JFK就即是出发机场又是到达机场)

day30 重新安排行程 N皇后 解数独_第1张图片

因此对容器有如下要求:1)可以对数据进行排序 2)容器容易增删元素 3)迭代器不能失效

unordered_map> targets

使用unordered_map<出发机场,map<到达机场,航班次数>> targets  使用航班次数做增减标记该机场是否使用过,若航班次数大于0,说明目的地还可以到达,若航班次数为0,则目的地不能到达了

2)回溯

回溯三部曲

1)参数和返回值   ticketnum航班的数量  返回值是bool 找到一个行程就返回即可

2)终止条件  只要找出一种行程即可,终止条件就是遇到机场的个数为航班的个数+1即可,说明这些航班都飞过了

3)单层递归逻辑

遍历一个出发机场对应的所有到达机场  只有这趟航班没有飞过时,即次数不为0时,才会飞

day30 重新安排行程 N皇后 解数独_第2张图片

代码

class Solution {
public:
    //出发机场->到达机场 航班次数
    unordered_map> targets;
    bool backtracking(int ticketsNum,vector& result){
        //终止条件  result中机场的数量为航班的数量+1 return
        if(result.size()==ticketsNum+1) return true;
        //单层递归逻辑
        //遍历一个出发机场对应的多个到达机场和航班次数  由于出发机场是key不可修改,所以const
        //target的结构是  到达机场,航班次数
        for(pair& target:targets[result[result.size()-1]]){
            //如果到达机场并没有到达过,也就是并没有飞过这趟航班
            if(target.second>0){
                result.push_back(target.first);//将到达机场收集到result中
                target.second--;   //该航班的次数要-1 因为已经飞过了
                if(backtracking(ticketsNum,result)) return true;//递归
                result.pop_back();//回溯
                target.second++;//回溯
            }
        }
        //遍历完这条航线上的某条航班路径没有满足终止条件的话,返回false
        return false;
    }
    vector findItinerary(vector>& tickets) {
        vector result;//存放最终所有的机场
        for(const vector& vec:tickets) targets[vec[0]][vec[1]]++;//一个出发机场对应到达机场的航班次数++,有无& 引用均可
        result.push_back("JFK");//先放入最起始的出发机场
        backtracking(tickets.size(),result);//航班数
        return result;
    }
};

代码(定义result全局变量)

class Solution {
public:
    //出发机场  到达机场 次数
    unordered_map> targets;
    vector result;
    result.push_back("JFK");//变量的初始化必须在函数体内部,这样是错误的
    bool backtracking(int ticketNum,vector& result){
        //终止条件  机场数量==航班数量 说明都飞完了
        if(result.size()==ticketNum+1) return true;
        //单层递归逻辑  这里一定要引用
        for(pair& target:targets[result[result.size()-1]]){
            if(target.second>0){
                result.push_back(target.first);//到达机场
                target.second--;//该机场已经飞过
                //这里有返回值 一定要这样 找到一条路径就返回
               if(backtracking(ticketNum,result)) return true;
                result.pop_back();
                target.second++;
            }
        }
        return false;
    }
    vector findItinerary(vector>& tickets) {
        for(vector vec:tickets) targets[vec[0]][vec[1]]++;//出发机场 到达机场对应的次数++
        // result.push_back("JFK");
        backtracking(tickets.size(),result);
        return result;
    }
};

会报如下错误

day30 重新安排行程 N皇后 解数独_第3张图片

result变量必须在函数体内部进行定义 于是将result的初始化放置在主函数内部,代码如下

class Solution {
public:
    //出发机场  到达机场 次数
    unordered_map> targets;
    vector result;
    bool backtracking(int ticketNum,vector& result){
        //终止条件  机场数量==航班数量 说明都飞完了
        if(result.size()==ticketNum+1) return true;
        //单层递归逻辑  这里一定要引用
        for(pair& target:targets[result[result.size()-1]]){
            if(target.second>0){
                result.push_back(target.first);//到达机场
                target.second--;//该机场已经飞过
                //这里有返回值 一定要这样 找到一条路径就返回
               if(backtracking(ticketNum,result)) return true;
                result.pop_back();
                target.second++;
            }
        }
        return false;
    }
    vector findItinerary(vector>& tickets) {
        for(vector vec:tickets) targets[vec[0]][vec[1]]++;//出发机场 到达机场对应的次数++
        result.push_back("JFK");//在函数体内部定义
        backtracking(tickets.size(),result);
        return result;
    }
};

题目2:51 N皇后

题目链接:51 N皇后

题意

将N个皇后放置在n*n的棋盘上 ,皇后彼此之间不在同一行,同一列或同一斜线上,返回N皇后的所有解决方案,方案中'Q'表示皇后,'.'表示空位

回溯

回溯三部曲:

1)参数和返回值

2)终止条件

3)单层递归逻辑

day30 重新安排行程 N皇后 解数独_第4张图片

判断皇后放置的位置是否合法

包含4种情况:1)同一列   2)同一行   3)45度斜线   4)135度斜线

day30 重新安排行程 N皇后 解数独_第5张图片

代码

class Solution {
public:
    vector> result;
    void backtracking(vector& chessboard,int row,int n){
        //终止条件 行数为n时  
        //row是从0开始的,所以当row遍历到最后一行时,如果满足N皇后的条件,那么会进入下一层递归row再+1,此时row==n
        //因此不存在chessborard不满足条件还放入result的可能
        if(row == n){
            result.push_back(chessboard);
            return;
        }
        //单层搜索逻辑
        for(int i=0;i& chessboard){
        //判断是否在同一列
        for(int i=0;i=0 && j>=0;i--,j--){
            if(chessboard[i][j]=='Q') return false;
        }
        //判断是否在135度线
        for(int i=row-1,j=col+1;i>=0 && j> solveNQueens(int n) {
        vector chessboard(n,string(n,'.'));//chessboard的每一行都是vector中的一个string元素,每个string元素又包含n个'.'
        backtracking(chessboard,0,n);
        return result;
    }
};
  • 时间复杂度: O(n!)
  • 空间复杂度: O(n)

题目3:解数独

题目链接:37 解数独

题意

1~9每一行只能出现一次,每一列只能出现一次,3*3宫格内只能出现一次  空格用'.'表示

判断数字放置的是否合法

day30 重新安排行程 N皇后 解数独_第6张图片

回溯

回溯三部曲:

1)参数和返回值

2)终止条件

3)单层递归逻辑

day30 重新安排行程 N皇后 解数独_第7张图片

伪代码 二维递归

day30 重新安排行程 N皇后 解数独_第8张图片

代码

class Solution {
public:
    bool isvalid(int row,int col,char k,vector>& board){
        //同一行有重复
        for(int j=0;j>& board){
        //终止条件 要遍历整棵树寻找
        //单层递归逻辑  因为每一个格都要填入数字,所以是二维递归
        for(int i=0;i>& board) {
        backtracking(board);
    }
};

你可能感兴趣的:(算法)