var longestIncreasingPath = (matrix, maxPath = 0) => {
const [ rows, cols ] = [ matrix.length, matrix[0].length ];
for (let row = 0; (row < rows); row++) {
for (let col = 0; (col < cols); col++) {
const path = dfs(matrix, row, rows, col, cols);
maxPath = Math.max(maxPath, path);
}
}
return maxPath;
}
var dfs = (matrix, row, rows, col, cols, ans = 0) => {
for (const [ _row, _col ] of getNeighbors(row, rows, col, cols)) {
const path = dfs(matrix, _row, rows, _col, cols);
ans = Math.max(ans, path);
}
ans += 1;
return ans;
}
var getNeighbors = (row, rows, col, cols) => [ [ 0, 1 ], [ 0, -1 ], [ 1, 0 ], [ -1, 0 ] ]
.map(([ _row, _col ]) => [ (row + _row), (col + _col) ])
.filter(([ _row, _col ]) => (0 <= _row) && (_row < rows) && (0 <= _col) && (_col < cols));
var longestIncreasingPath = (matrix, maxPath = 0, memo = initMemo(matrix)) => {
const [ rows, cols ] = [ matrix.length, matrix[0].length ];
for (let row = 0; row < rows; row++) {
for (let col = 0; col < cols; col++) {
const path =
search(matrix, row, rows, col, cols, memo);
maxPath = Math.max(maxPath, path);
}
}
return maxPath;
};
var initMemo = (matrix) => new Array(matrix.length).fill()
.map(() => new Array(matrix[0].length).fill(0));
const search = (matrix, row, rows, col, cols, memo) => {
const hasSeen = (memo[row][col] !== 0)
if (hasSeen) return memo[row][col];
return dfs(matrix, row, rows, col, cols, memo);
}
var dfs = (matrix, row, rows, col, cols, memo) => {
for (const [ _row, _col ] of getNeighbors(row, rows, col, cols)) {
const [ parent, node ] = [ matrix[row][col], matrix[_row][_col] ];
const isLess = (node <= parent);
if (isLess) continue;
const path = search(matrix, _row, rows, _col, cols, memo);
memo[row][col] = Math.max(memo[row][col], path);
}
memo[row][col] += 1;
return memo[row][col];
}
var getNeighbors = (row, rows, col, cols) => [ [ 0, 1 ], [ 0, -1 ], [ 1, 0 ], [ -1, 0 ] ]
.map(([ _row, _col ]) => [ (row + _row), (col + _col) ])
.filter(([ _row, _col ]) => (0 <= _row) && (_row < rows) && (0 <= _col) && (_col < cols));
var longestIncreasingPath = (matrix) => {
const { graph, indegree, sources } =
buildGraph(matrix);
findSources(graph, indegree, sources);
return bfs(graph, indegree, sources);
}
const initGraph = (rows, cols) => ({
graph: new Array((rows + 2)).fill()
.map(() => new Array((cols + 2)).fill(0)),
indegree: new Array((rows + 2)).fill()
.map(() => new Array((cols + 2)).fill(0)),
sources: new Queue()
})
var buildGraph = (matrix) => {
const [ rows, cols ] = [ matrix.length, matrix[0].length ];
const { graph, indegree, sources } =
initGraph(rows, cols);
for (let row = 1; (row < (rows + 1)); row++) {
graph[row] = [ 0, ...matrix[row - 1], 0 ];
}
for (let row = 1; (row <= rows); row++) {
for (let col = 1; (col <= cols); col++) {
for (const [ _row, _col ] of getNeighbors(row, col)) {
const isSink = (graph[row][col] < graph[_row][_col]);
if (isSink) indegree[row][col] += 1;
}
}
}
return { graph, indegree, sources };
}
var getNeighbors = (row, col) => [ [ 0, 1 ], [ 0, -1 ], [ 1, 0 ], [ -1, 0 ] ]
.map(([ _row, _col ]) => [ (row + _row), (col + _col) ]);
var findSources = (graph, indegree, sources) => {
const [ rows, cols ] = [ graph.length, graph[0].length ];
for (let row = 1; (row < (rows - 1)); ++row) {
for (let col = 1; (col < (cols - 1)); ++col) {
const isSource = (indegree[row][col] === 0);
if (isSource) sources.enqueue([ row, col ]);
}
}
}
const bfs = (graph, indegree, sources, path = 0) => {
while (!sources.isEmpty()) {
for (let level = (sources.size() - 1); 0 <= level; level--) {
checkNeighbors(graph, indegree, sources)
}
path += 1;
}
return path;
}
const checkNeighbors = (graph, indegree, sources) => {
const [ row, col ] = sources.dequeue();
for (const [ _row, _col ] of getNeighbors(row, col)) {
const canDisconnect = (graph[_row][_col] < graph[row][col]);
if (!canDisconnect) continue;
indegree[_row][_col] -= 1;
const isSource = (indegree[_row][_col] === 0);
if (isSource) sources.enqueue([ _row, _col ]);
}
}