LeetCode刷题系列-785. 判断二分图

题目

leetcode传送门

给定一个无向图graph,当这个图为二分图时返回true

如果我们能将一个图的节点集合分割成两个独立的子集AB,并使图中的每一条边的两个节点一个来自A集合,一个来自B集合,我们就将这个图称为二分图。

graph将会以邻接表方式给出,graph[i]表示图中与节点i相连的所有节点。每个节点都是一个在0graph.length-1之间的整数。这图中没有自环和平行边:graph[i] 中不存在i,并且graph[i]中没有重复的值。

注意点:

  • graph 的长度范围为 [1, 100]
  • graph[i] 中的元素的范围为[0, graph.length - 1]
  • graph[i] 不会包含 i 或者有重复的值。
    图是无向的: 如果jgraph[i]里边, 那么 i 也会在 graph[j]里边。

解题思路

算法的流程如下:

  • 我们任选一个节点开始,将其染色,并从该节点开始对整个无向图进行遍历;

  • 在遍历的过程中,如果我们通过节点 u 遍历到了节点 v(即 uv 在图中有一条边直接相连),那么会有两种情况:

    • 如果 v 未被染色,那么我们将其染成与 u 不同的颜色,并对 v 直接相连的节点进行遍历;

    • 如果 v 被染色,并且颜色与 u 相同,那么说明给定的无向图不是二分图。我们可以直接退出遍历并返回False 作为答案。

  • 当遍历结束时,说明给定的无向图是二分图,返回 True 作为答案。

解法一:广度优先算法

因为题目给的是邻接表,天生适合广度优先算法。

// 广度遍历 bfs
var isBipartite1 = function(graph) {
    
    
  const colors = new Array(graph.length).fill("N"); // 记录顶点染色,初始化未染色'N',颜色分别是'Y'和'R'
  const queue = []; // 辅助队列

  let index = 0; // 当前顶点
  while (index !== -1) {
    
    
    colors[index] = "Y"; // 染色
    queue.push(index); // 顶点加入队列中
    while (queue.length > 0) {
    
    
      let node = queue.shift(); // 出队
      let borderNodeList = graph[node];
      let paintColor = colors[node] === "Y" ? "R" : "Y";
      // 遍历当前顶点的邻接顶点,判断能否染色
      for (let i = 0, len = borderNodeList.length; i < len; ++i) {
    
    
        if (colors[borderNodeList[i]] === "N") {
    
    
          colors[borderNodeList[i]] = paintColor;
          queue.push(borderNodeList[i]);
        } else if (colors[borderNodeList[i]] !== paintColor) {
    
    
          return false;
        }
      }
    }
    index = colors.indexOf("N");
  }
  return true;
};

解法二:深度优先算法

将大问题分解为一个个子问题,每个子问题的核心是:判断当前顶点v能否正常染色,且其相邻节点能否正常染色。

假设f(i)表示当前顶点i可否正常染色,那么f(i) = f(i) && f(adjoin(i))

const dfs = (v, graph, colors, color) => {
    
    
  // 递归出口
  if (colors[v] !== "N") {
    
    
    if (colors[v] !== color) {
    
    
      return false;
    }
    return true;
  }
  // 核心,判断当前节点能否
  colors[v] = color;
  return graph[v].every(item =>
    dfs(item, graph, colors, color === "Y" ? "R" : "Y")
  );
};

const isBipartite2 = function(graph) {
    
    
  let colors = new Array(graph.length).fill("N");
  return colors.every((item, index) =>
    item === "N" ? dfs(index, graph, colors, "Y") : true
  );
};

也可以用栈模拟递归。

// 深度遍历(迭代写法)
var isBipartite = function(graph) {
    
    
  const colors = new Array(graph.length).fill("N");
  const stack = [];

  let index = 0;
  while (index !== -1) {
    
    
    colors[index] = "Y";
    stack.push(index);
    while (stack.length > 0) {
    
    
      let node = stack.pop();
      let borderNodeList = graph[node];
      let paintColor = colors[node] === "Y" ? "R" : "Y";
      for (let i = 0, len = borderNodeList.length; i < len; ++i) {
    
    
        if (colors[borderNodeList[i]] === "N") {
    
    
          colors[borderNodeList[i]] = paintColor;
          stack.push(borderNodeList[i]);
        } else if (colors[borderNodeList[i]] !== paintColor) {
    
    
          return false;
        }
      }
    }
    index = colors.indexOf("N");
  }
  return true;
};

猜你喜欢

转载自blog.csdn.net/sinat_36521655/article/details/107394033