今天的三道题重点掌握N皇后,二刷看其他两道。

332.重新安排行程(hard)

一刷搞清楚几个问题就行,容器的使用这有点麻烦。

alt

  • 一个行程中,如果航班处理不好容易变成一个圈,成为死循环。 先遍历记录所有机场能够走的次数,利用次数>0避免循环,如果“航班次数”大于零,说明目的地还可以飞,如果“航班次数”等于零说明目的地不能飞了,而不用对集合做删除元素或者增加元素的操作。
  • 有多种解法,字母序靠前排在前面,让很多同学望而退步,如何该记录映射关系呢 使用map记录顺序
  • 使用回溯法(也可以说深搜) 的话,那么终止条件是什么呢?结果集的大小 = 机票数量 + 1 代表所机票涵盖的有机场(可能有重复)都走过一遍了
  • 搜索的过程中,如何遍历一个机场所对应的所有机场。 使用unorderedmap
class Solution {
public:
    unordered_map<string, map<string, int>> targets;
    vector<string> findItinerary(vector<vector<string>>& tickets) {
        targets.clear();
        vector<string> result;
        for (const vector<string>& vec : tickets) {
            targets[vec[0]][vec[1]]++;
        }
        result.push_back("JFK");
        BackTracking(tickets.size(), result);
        return result;
    }
    bool BackTracking(int ticketNum, vector<string>& result) {
        if (result.size() == ticketNum + 1) {
            return true;
        }
        for (pair<const string, int>& 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;
    }
};

N皇后

棋盘的宽度就是for循环的长度,递归的深度就是棋盘的高度,主要难点在回溯处理的是二维的棋盘了。

  • 注意递归行不用判断重复,因为每次只在每一行放一个,需要判断同列,左上对角,右上对角是否有重复。

自己按照回溯的思路写出来的,太棒了。

alt

//C++
class Solution {
public:
    vector<vector<string>> res;
    vector<vector<string>> solveNQueens(int n) {
        res.clear();
        vector<string> chessboard(n, string(n, '.'));
        BackTracking(n, 0, chessboard);
        return res;
    }
    void BackTracking(int n, int row, vector<string>& chessboard) {
        if (row == n) {
            res.push_back(chessboard);
            return;
        }
        for (int i = 0; i < n; i++) {
            if (isValid(row, i, chessboard, n)) {
                chessboard[row][i] = 'Q';
                BackTracking(n, row + 1, chessboard);
                chessboard[row][i] = '.';
            }
        }
    }
    bool isValid(int row, int col, vector<string>& chessboard, int n) {
        for (int i = 0; i < row; i++) {
            if (chessboard[i][col] == 'Q') {
                return false;
            }
        }
        for (int i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--) {
            if (chessboard[i][j] == 'Q') {
                return false;
            }
        }
        for (int i = row - 1, j = col + 1; i >= 0 && j < n; i--, j++) {
            if (chessboard[i][j] == 'Q') {
                return false;
            }
        }
        return true;
    }
};

C# 的List不像vector容器可以初始化和指定默认值,Fill的方式还得把string转成char数组,直接charchar记录棋盘,最后还得用StringBulider转回sting的List,注意C#里二维交错数组要单独new分配空间。

  • 判断是否有皇后对角线要从点出发向左上右上检查,不能从两个头检查,当前点不一定就在正对角线上。
//C#
public class Solution {
    IList<IList<string>> res = new List<IList<string>>();
    public IList<IList<string>> SolveNQueens(int n) {
        //这是交错数组
        char[][] board = new char[n][];
        for (int i = 0; i < n; i++) {
            board[i] = new char[n];
        }
        foreach(char[] item in board) {
            Array.Fill(item, '.');
        }
        BackTracking(0, n, board);
        return res;
    }

        public List<string> ToIList(char[][] board){
        List<string> list = new List<string>();
        StringBuilder sb = new StringBuilder();
        foreach(char[] chess in board){
            foreach(var ch in chess)
                sb.Append(ch);
            list.Add(sb.ToString());
            sb.Clear();
        }
        return list;
    }
    public void BackTracking(int row, int n, char[][] chessboard) {
        if (row == n) {
            res.Add(ToIList(chessboard));
            return;
        }
        for (int col = 0; col < n; col++) {
            if (isValid(row, col, n, chessboard)) {
                chessboard[row][col] = 'Q';
                BackTracking(row + 1, n, chessboard);
                chessboard[row][col] = '.';
            }
        }
    }
    public bool isValid(int row, int col, int n, char[][] chessboard) {
        for (int i = 0; i < row; i++) {
            if (chessboard[i][col] == 'Q') return false;
        }
        for (int i = row - 1, j = col - 1; i >= 0 && j >=0; i--, j--) {
            if (chessboard[i][j] == 'Q') return false;
        }

        for (int i = row - 1, j = col + 1; i >= 0 && j < n; i--, j++) {
            if (chessboard[i][j] == 'Q') return false;
        }
        //for (int i = 0, j = 0; i < row && j < col; i++, j++) {
        //   if (chessboard[i][j] == 'Q') return false;
        //}
        //for (int i = n - 1, j  = n - 1; i < row && j > col; i++, j--) {
        //    if (chessboard[i][j] == 'Q') return false;
        //}

        return true;
    }
}

37. 解数独

二维递归,二刷再看,合理条件和二维递归的思想是核心。