-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathunique-paths-ii.cpp
121 lines (111 loc) · 4.33 KB
/
unique-paths-ii.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
/*
* Copyright (c) 2018 Christopher Friedt
*
* SPDX-License-Identifier: MIT
*/
#include <vector>
using namespace std;
class Solution {
public:
// https://leetcode.com/problems/unique-paths-ii/
int uniquePathsWithObstacles(vector<vector<int>> &obstacleGrid) {
// Assumptions
// - all directions allowed (i later reread the question and saw that)
// my assumption was invalid. Oh well, I have a generalized answer
// - goal is not to find optimal paths, but all paths (see above)
// - no irregular vectors in argument
// - N rows, M columns
// - cell contents are either 0 or 1
//
// Observations
// - kind of like a graph and adjacency matrix
// - not a DAG - has cycles (actually, it is a DAG now, see above)
// - depth first search / recursion likely a good solution
// - However, if there are no obstacles, it reduces to nCk
// - If there are obstacles on the start or finish spaces, there
// are zero paths.
//
// Analysis
// - brute force would likely be in the order of O(N^4) or something
// I won't even bother.
// - Using DFS, we have O( |N| + |E| ), where N are the number of
// spaces on the graph, and E are the number of edges (I guess these
// are a vector and a matrix).
// - Will need to detect cycles, so keep a collection of visited nodes
// for each path (max size is M)
// - Will need to keep a set of unique paths - size P. They will all
// have a length M, since we are limited to Down / Right.
// - It will take O( N ) time to build the graph, where N is the number
// of nodes.
//
// Further DFS Analysis
//
// - The upper bound on the number of paths that would need to be
// stored would be when there are no obstacles,
// so up to C( M + N - 2, M - 1 ) paths.
// - That can be a lot, so storage of those paths would be an issue
// at larger sizes.
// - For a 10x10 grid, that's "only" 48,620 paths to store.
// - For a 20x20 grid, that quickly blows up to 35 billion!!!
// - For the purpose of this problem, we likely don't need to remember
// the individual paths so much as just count how many there are, so
// DFS is already likely overkill here.
// - There will be a maximum of M * N nodes contributing to the time
// complexity making it at least O( N^2 ). Bad but better than the
// brute force method (so far).
// - If the only two directions allowed are Down and Right, then
// the upper bound on the number of edgest is expressable as
// M*N - N - M.
// - Therefore, the total time complexity of this approach is something
// on the order of O( 2MN - M - N ), so still approximately O( N^2 ).
// - For a DFS
// maximum
//
// OK, throw DFS into the garbage.
//
// The best we're likely going to see is linear on the number of spaces
// in the grid, or more precisely, O( MN ). We can only visit each node
// once.
//
// I had to look at the solution to get the algorithm, so here goes.
//
// The trick is, that it is only possible to get to a given cell
// from the cell above it or the cell to the left of it.
//
// We can keep track of the number of ways to get to a cell by keeping a
// record in all non-obstacle cells.
//
// Obstacle cells should be set to zero when we encounter them since there
// is no way that any path that leads to them can contribute to the total
// number of paths.
size_t M = obstacleGrid.size();
size_t N = (0 == M) ? 0 : obstacleGrid[0].size();
if (0 == N || 0 == M) {
return 1;
}
for (size_t row = 0; row < M; row++) {
for (size_t col = 0; col < N; col++) {
if (0 == row && 0 == col) {
if (1 == obstacleGrid[row][col]) {
return 0;
}
obstacleGrid[row][col] = 1;
continue;
}
if (1 == obstacleGrid[row][col]) {
obstacleGrid[row][col] = 0;
continue;
}
size_t sum = 0;
if (col > 0 && obstacleGrid[row][col - 1] != 0) {
sum += obstacleGrid[row][col - 1];
}
if (row > 0 && obstacleGrid[row - 1][col] != 0) {
sum += obstacleGrid[row - 1][col];
}
obstacleGrid[row][col] = sum;
}
}
return obstacleGrid[M - 1][N - 1];
}
};