Friday, December 20, 2013

Day 60, #51, #52, #54, N-Queens, N-Queens II, Spiral Matrix

N-Queens
The n-queens puzzle is the problem of placing n queens on an n×n chessboard such that no two queens attack each other.

Given an integer n, return all distinct solutions to the n-queens puzzle.
Each solution contains a distinct board configuration of the n-queens' placement, where 'Q' and '.' both indicate a queen and an empty space respectively.
For example,
There exist two distinct solutions to the 4-queens puzzle:
[
 [".Q..",  // Solution 1
  "...Q",
  "Q...",
  "..Q."],

 ["..Q.",  // Solution 2
  "Q...",
  "...Q",
  ".Q.."]
]
----------------------------------------------------------------------
Typical DFS. Set up 3 vector<bool>s to indicate conflict
Red is backslash
Blue is slash
Green is row


class Solution {
public:
    void queens(vector<vector<string> > &ret,vector<bool> &slash, vector<bool> &backslash, vector<bool> &usedRow, vector<string> cur, int col, int n) {
        if (col == n) {
            ret.push_back(cur);
            return;
        }

        for (int row = 0; row < n; row++) {

            // check conflicts in diagonals and same row
            if (slash[col + row] && backslash[row-col + n] && usedRow[row]) {
                cur[row][col] = 'Q';
                slash[col + row] = false;
                backslash[row-col + n] = false;
                usedRow[row] = false;
                queens(ret,slash,backslash,usedRow,cur,col+1,n);
                
                // backtrack
                cur[row][col] = '.';
                slash[col + row] = true;
                backslash[row-col + n] = true;
                usedRow[row] = true;
            }
        }
    }

    vector<vector<string> > solveNQueens(int n) {
        vector<vector<string> > ret;
        vector<bool> slash(n*2,true);
        vector<bool> backslash(n*2,true);
        vector<bool> usedRow(n,true);
        
        // populate vectors
        string str = "";
        for (int i = 0; i < n; i++) {
            char c = '.';
            str += c;
        }
        vector<string> cur(n,str);
        
        queens(ret,slash,backslash,usedRow,cur,0,n);
        return ret;
    }
};
Update Feb-10-2015
Using bit operation
class Solution {
public:
    string getString(int n, int p) {
        string s(n,'.');
        s[p] = 'Q';
        return s;
    }

    void queens(vector<vector<string> > &rt, vector<string> cur,int slash, int backSlash, int row, int n) {
        int upperLimit = (1 << n) - 1;
        if (row == upperLimit) {
            rt.push_back(cur);
            return;
        }
        
        int possiblePositions = upperLimit & (~(slash | backSlash | row));
        int itr = possiblePositions;
        int p = n - 1;
        while (possiblePositions != 0) {
            int rightMost = possiblePositions & (-possiblePositions);
            if (itr & 1) {
                string s = getString(n,p);
                vector<string> temp = cur;
                temp.push_back(s);
                possiblePositions -= rightMost;
                
                queens(rt,temp,(slash + rightMost) << 1,(backSlash + rightMost) >> 1,row + rightMost,n);
            }
            p--;
            itr >>= 1;
        }
    }

    vector<vector<string> > solveNQueens(int n) {
        vector<vector<string> > rt;
        vector<string> cur;
        queens(rt,cur,0,0,0,n);
        
        return rt;
    }
};

Java, updated on Sep-8th-2018
O(n!)
T(n) = n * T(n - 1)

class Solution {
    public List> solveNQueens(int n) {
        boolean[] cols = new boolean[n];
        boolean[] diag = new boolean[n * 2]; // row + col
        boolean[] antiDiag = new boolean[n * 2]; // row - col + n - 1
        
        List> rt = new ArrayList<>();
        dfs(0, n, new ArrayList(), rt, cols, diag, antiDiag);
        
        return rt;
    }
    
    private void dfs(int row, int n, List sofar, List> rt,
                    boolean[] cols, boolean[] diag, boolean[] antiDiag) {
        
        if (row >= n) {
            rt.add(sofar);
            return;
        }
                
        String cur = "";
        for (int i = 0; i < n; i++) {
            if (!cols[i] && !diag[row + i] && !antiDiag[row - i + n - 1]) {
                cols[i] = true;
                diag[row + i] = true;
                antiDiag[row - i + n - 1] = true;
            
                String tmp = cur + "Q";
                for (int j = i + 1; j < n; j++) tmp += "."; 
                List tmpSofar = new ArrayList<>(sofar);
                tmpSofar.add(tmp);
                
                dfs(row + 1, n, tmpSofar, rt, cols, diag, antiDiag);
                
                cols[i] = false;
                diag[row + i] = false;
                antiDiag[row - i + n - 1] = false;
            }
            
            cur += ".";
        }
    }
}

N-Queens II
Follow up for N-Queens problem.
Now, instead outputting board configurations, return the total number of distinct solutions.
---------------------------------------------------------------------
Solution #1 similar to previous problem
Note that usedRow[row] should be checked first otherwise it exceeds OJ's  time limit
class Solution {
public:
void queens(int &ret,vector<bool> &slash, vector<bool> &backslash, vector<bool> &usedRow, int col, int n) {
        if (col == n) {
            ret++;
            return;
        }

        for (int row = 0; row < n; row++) {
            if (usedRow[row] && slash[col + row] && backslash[row-col + n]) {
                slash[col + row] = false;
                backslash[row-col + n] = false;
                usedRow[row] = false;
                queens(ret,slash,backslash,usedRow,col+1,n);
                
                // backtrack
                slash[col + row] = true;
                backslash[row-col + n] = true;
                usedRow[row] = true;
            }
        }
    }

    int totalNQueens(int n) {
        vector<bool> slash(n*2,true);
        vector<bool> backslash(n*2,true);
        vector<bool> usedRow(n,true);
        
        int ret = 0;
        queens(ret,slash,backslash,usedRow,0,n);
        return ret;
    }
};
Solution #2
http://www.matrix67.com/blog/archives/266  

Update on Nov-13-2014 
基本思路为DFS
~(row | slash | backSlash) 代表每行上的可放位置,当切入到下一行时,slash跟backSlash分别需要位移一位
possiblePosition 代表当前行所有可放入棋子的位置
rightMostOne 代表当前放入棋子的位置
拿一个例子走一遍代码,立即能明白此算法
class Solution {
public:
    void bitOP(int &num, int row, int slash, int backSlash, int n) {
        int upperLimit = (1 << n) - 1; // upperLimit has n of '1'
        if (row == upperLimit) {
            num++;
            return;
        }
        
        int possiblePosition = upperLimit & (~(row | slash | backSlash)); // get posiible positions for queen in a row
        while (possiblePosition != 0) {
            int rightMostOne = possiblePosition & (-possiblePosition); // get the most right '1' as new queen's position
            possiblePosition -= rightMostOne;
            bitOP(num, row + rightMostOne, (slash + rightMostOne) << 1, (backSlash + rightMostOne) >> 1,n);
        }
        
    }

    int totalNQueens(int n) {
        int num = 0;
        bitOP(num,0,0,0,n);
        return num;
    }
};
Spiral Matrix
Given a matrix of m x n elements (m rows, n columns), return all elements of the matrix in spiral order.
For example,
Given the following matrix:
[
 [ 1, 2, 3 ],
 [ 4, 5, 6 ],
 [ 7, 8, 9 ]
]
You should return [1,2,3,6,9,8,7,4,5].
-----------------------------------------------------------
Similar to #59, Spiral Matrix II
start at the outer most layer
class Solution {
public:
    void spiral (vector<vector<int> > &matrix, vector<int> &ret, int m, int n, int k) {
        if (m <= 0 || n <= 0) {
            return;
        }
        
        if (m == 1) {
            for (int i = 0; i < n; i++) {
                ret.push_back(matrix[k][k + i]);
            }
            return;
        }
        
        if (n == 1) {
            for (int i = 0; i < m; i++) {
                ret.push_back(matrix[k + i][k]);
            }
            return;
        }
        
        // going right
        for (int i = 0; i < n - 1; i++) {
            ret.push_back(matrix[k][i + k]);    
        }
        
        // going down
        for (int i = 0; i < m - 1; i++) {
            ret.push_back(matrix[k + i][n - 1 + k]);
        }
        
        // going left
        for (int i = 0; i < n - 1; i++ ) {
            ret.push_back(matrix[m - 1 + k][n - 1 + k - i]);
        }
        
        // going up
        for (int i = 0; i < m - 1; i++ ) {
            ret.push_back(matrix[k + m - 1 - i][k]);
        }
        
        spiral(matrix,ret,m-2,n-2,k+1);
    }

    vector<int> spiralOrder(vector<vector<int> > &matrix) {
        int m = matrix.size();
        vector<int> ret;
        if (m == 0) return ret;
        int n = matrix[0].size();
        spiral(matrix,ret,m,n,0);
        return ret;
    }
};

No comments:

Post a Comment