【发布时间】:2021-05-13 12:53:45
【问题描述】:
假设我得到了pairs 的array(其中pair[0] 取决于pair[1])。我想检测任何对依赖项之间是否存在循环。
周期:
[[0,1], [1,2], [2, 1]]
说明:1 -> 2和2 -> 1之间有一个循环
不是循环:
[[0,1], [1,2], [0, 2]]
TLDR;
我遇到的问题是......一旦我“检测到”了一个循环,我似乎无法弄清楚如何“返回”它。调用堆栈继续执行“其他”子级,但我希望它停止。
您可以跳到底部(算法)
方法:
- 使用
Map✅ 创建对的图形表示
/**
* @param { array } [ [intA, intB] ] - Nested array of integers pairs
* @return { Map } (representing a Graph)
*/
function createGraph(array) {
const nodes = new Map();
// Create Verticies
array.map(pair => {
const aClass = pair[0];
const bClass = pair[1];
nodes.set(aClass, []);
nodes.set(bClass, []);
})
// Create Edges
array.map(pair => {
const aClass = pair[0];
const bClass = pair[1];
nodes.get(aClass).push(bClass);
});
return nodes;
}
到目前为止,它按预期工作:
// Create Graph
const array = [[0,1], [1,2], [0, 2]];
const graph = createGraph(array);
console.log(graph);
// Map(3) { 0 => [ 1, 2 ], 1 => [ 2 ], 2 => [] }
- 对所有未访问的节点(在
GreySet中)进行 DFS(直到我们检测到一个循环)。 ⚠️
我使用了 3 Colored Set 方法。我真的很喜欢算法并且真的希望实现它。 据我了解如下。
-
WhiteSet包含所有未被触及的节点。 -
GreySet包含当前正在探索的节点。因此,在我们的 DFS 中,“父”将保留在该集合中。 -
BlackSet将保存已经探索过的节点(直到没有循环的地步)。
所以...如果我们探索BlackSet 中的一个孩子,我们没有理由进一步探索它(它已经探索过了,而且它没有任何循环)。 但是,如果我们遇到一个不在 WhiteSet 中的子节点并且它存在于 GreySet 中,这意味着我们有一个循环。
这是我的代码,我在下面添加了console.logs。 我遇到的问题是......一旦我“检测到”了一个循环,我似乎无法弄清楚如何“返回”它。它会继续执行,如您所见。
算法:
// Create Graph
const graph = createGraph(array);
console.log(graph); // Looks Good
// Detect Cycle
// Create 3 Sets
const whtSet = new Set(graph.keys()); // Put all the Integer "node values" the set.
const grySet = new Set();
const blkSet = new Set();
const unvisitedValues = whtSet.keys(); // Iterator
while (whtSet.size > 0) {
const doesItHaveCycle = hasCycle(unvisitedValues.next().value); // Expore any unexplored nodeVal
console.log('whtSet', whtSet);
console.log('grySet', grySet);
console.log('blkSet', blkSet);
console.log('does it have a cycle', doesItHaveCycle);
}
function hasCycle(nodeVal) {
// Blackset means it has been compltely explored :)
if (blkSet.has(nodeVal)) return false;
// This means we have found a cycle
if (!whtSet.has(nodeVal) && grySet.has(nodeVal)) return true;
// Remove it from the whiteSet, into the greySet.
whtSet.delete(nodeVal);
grySet.add(nodeVal);
// Recurse Children
graph.get(nodeVal).forEach((child) => {
let doesHaveCycle = hasCycle(child);
console.log(
'doesHaveCycle result: ',
doesHaveCycle,
'when exploring nodeVal',
nodeVal,
'and child',
child
);
if (doesHaveCycle === true) return true; // RETURN THIS PLS lol
});
// If above was true, I DO NOT want it to come here, but it still does.
console.log('if above was true... shouldnt come here');
// Now, that we have explored all of the children, remove it from Grey Set...
// Add it to the Black Set
grySet.delete(nodeVal);
blkSet.add(nodeVal);
return false; // IDK
}
console.log的结果
doesHaveCycle result: true when exploring nodeVal 2 and child 1
if above was true... shouldnt come here
doesHaveCycle result: false when exploring nodeVal 1 and child 2
if above was true... shouldnt come here
doesHaveCycle result: false when exploring nodeVal 0 and child 1
if above was true... shouldnt come here
whtSet Set(0) {}
grySet Set(0) {}
blkSet Set(3) { 2, 1, 0 }
does it have a cycle false
我 100% 开放修改代码,现在一团糟。但是,我还是想用“3 Color Set”的方式。
关于更多上下文,我试图解决这个名为Course Schedule 的可爱算法问题。
【问题讨论】:
标签: javascript algorithm recursion set