18. Place N Cameras Without Conflict on Blocked Grid
Origin: Place N Cameras Without Conflict on Blocked Grid
Given an NxN grid where 0 is empty and 1 is blocked, return true if N cameras can be placed on empty cells such that no two share the same row, column, or diagonal.
本质上是 N 皇后问题,grid 里的 1 表示该格被阻挡(不能放相机)。
Example 1
Input: N = 4, grid = [[0,0,0,0], [0,0,0,0], [0,0,0,0], [0,0,0,0]]
Output: True
Explanation: One valid placement: Row 0→col 1, Row 1→col 3, Row 2→col 0, Row 3→col 2. No two share row, column, or diagonal.
Example 2
Input: N = 4, grid = [[0,1,0,0], [0,0,0,1], [1,0,0,0], [0,0,1,0]]
Output: True
Explanation: Some cells are blocked (marked 1). Placement: Row 0→col 2, Row 1→col 0, Row 2→col 3, Row 3→col 1. All on empty cells, no conflicts.
Input Format
- N(整数,网格大小)
- grid_rows(整数,行数 = N)
- grid_columns(整数,列数 = N)
- 接下来 grid_rows 行,每行 grid_columns 个整数(0 或 1)
Constraints
- 1 <= N <= 15
- grid.length == N
- grid[i].length == N
- grid[i][j] ∈ {0, 1}
Output Format
Return a single boolean value (true or false) indicating whether a valid arrangement of N cameras exists.
Sample Input 0
1
1
1
0
Sample Output 0
1
Sample Input 1
2
2
2
0 1
1 0
Sample Output 1
0
函数契约
// 输入:N(网格大小),grid(NxN 的 0/1 矩阵,1 表示阻挡)
// 输出:true 或 false(能否放 N 个相机,互不攻击)
// 边界:N=1 且 grid[0][0]=0 → true;N=1 且 grid[0][0]=1 → false
边界表
| 场景 | 返回什么 |
|---|---|
| N=1, grid[0][0]=0 | true |
| N=1, grid[0][0]=1 | false |
| 全部阻挡 | false |
| 无解 | false |
| 有解 | true |
Resolution
我的解法
function canPlaceSecurityCameras(N: number, grid: number[][]): boolean {
let res = false
const placeCamera = (row: number, cols: number[], diag1s: number[], diag2s: number[]) => {
if (res) return // 已找到解,提前退出
for (let i = 0; i < N; i++) {
const isPlaceable = grid[row][i] === 0 && !cols.includes(i) && !diag1s.includes(row - i) && !diag2s.includes(row + i)
if (row === N - 1 && isPlaceable) {
res = true
return
}
if (isPlaceable) {
placeCamera(row + 1, [...cols, i], [...diag1s, row - i], [...diag2s, row + i])
}
}
}
placeCamera(0, [], [], [])
return res
}解题思路
逐行放置,每行选一个列。用三个数组记录冲突:
cols:已占用的列diag1s:已占用的主对角线(row - col 相同)diag2s:已占用的副对角线(row + col 相同)
对每个格子检查四个条件:grid 为空(值为 0)、列不冲突、主对角线不冲突、副对角线不冲突。全部满足才能放。放到最后一行说明 N 个相机全部放完,返回 true。
找到解后用 if (res) return 提前退出,N=15 时能省大量递归。
对角线判断原理
同一条主对角线上的格子,row 和 col 的差值相同。比如 (0,0)、(1,1)、(2,2) 差值都是 0;(0,2)、(1,3) 差值都是 -2。
同一条副对角线上的格子,row 和 col 的和相同。比如 (0,2)、(1,1)、(2,0) 和都是 2。
所以用 row - col 标识主对角线,row + col 标识副对角线,放相机时把对应值加入冲突列表,后续格子检查是否在列表中即可。
踩坑经历
第一版递归传参用了函数参数 col 而不是循环变量 i,导致冲突列表存的是错误的值。修正后把 col 参数去掉,直接用循环变量 i 传递。
复杂度
- 时间:O(N!),每行可选列数递减(N × (N-1) × (N-2) × … × 1)
- 空间:O(N),递归栈深度 N,三个冲突列表各最多 N 个元素
测试用例
| 输入 | 输出 | 场景 |
|---|---|---|
| N=1, grid=0 | true | 单格可放 |
| N=1, grid=1 | false | 单格阻挡 |
| N=2, grid=[[0,1],[1,0]] | false | 2x2 无解 |
| N=4, grid=全0 | true | 4x4 全空 |
| N=4, grid=有阻挡 | true | 4x4 有阻挡 |
| N=3, grid=全1 | false | 全阻挡 |
全部通过。
参考来源
- 相关题型:回溯算法
- 相关文章:算法解题流程:从读题到提交的七步
- 相关题目:13. Generate Valid Angle Bracket Sequences — 回溯系列
- 相关题目:17. Lexicographical Letter Combinations of Phone Digits — 回溯系列