每日一题算法: 2020年7月16日 [判断二分图] isBipartite

本文介绍了如何解决LeetCode上的判断二分图问题,通过解题思路、示例分析及代码实现,详细阐述了如何判断一个图是否能分割为两个独立的子集,即构成二分图。文中提到了二分图的特点,并讨论了暴力求解和优化后的递归解法,以及解题过程中需要注意的问题。
摘要由CSDN通过智能技术生成

2020年7月16日 判断二分图 isBipartite

在这里插入图片描述

默认格式:

class Solution {
    public boolean isBipartite(int[][] graph) {

    }
}

解题思路:

这道题比较抽象,我们先尽可能多地挖掘信息。

graph[i]表示的是和i相连的点的值。

比如题中的graph[0]={1,2,3}表示0和1,2,3相连

所有的数都是连续的,并且不会出现重复。

问题1:

什么叫做分割为两个独立的子集。也就是所谓的二分图。

特点有以下两点。

每一条边的两端,分别在两个独立的子集中,子集中存的是部分的节点的集合,两个子集加起来就是所有节点的集合。

也许这么说会比较清楚:

我们先看示例1:

在这里插入图片描述

通过graph[0]={1,3}我们知道,0和3有一条边,0和1也有一条边,所以我们可以确定0和1、3不是在同一个子集中。

继续看graph[1]={0,2},我们知道了1和0不在同一个子集中,同时,1和2也不在同一个子集中,所以,目前我们可以知道1和3在同一个子集中,0和2在一个子集中,不过这还没完,因为我们没有遍历完所有的节点,我们需要遍历所有节点,确定后面不会出现矛盾的选项才可以(实际上不需要,如果2或者3和其他节点有相连,比如2和0有相连,那么在0中就必定存在2,而0的连接点没有2,所有可以推出2和0不相连)

然后看一个示例2:
在这里插入图片描述

通过graph[0]={1,2,3}我们知道,0和1,2,3都是相连的,所以,如果要分子集,只能是{0},{1,2,3},但是看第二个,graph[1]={0,2}我们又发现1和2也是相连的,所以1和2不能在同一个子集中,这样和之前的结论就产生矛盾了,说明这不是一个二分图。

实现:

暴力实现,使用逆推的方式,首先遍历所有一级数组,得到和i相连的所有点,把i放入分组a中,把和i相连的放入分组b中。每一个数放入之前先判断另一个分组中是否已经有存在,如果存在直接返回false证明二分图不能构成。

当然,分组存数据用的是HashSet,判断是否存在比较方便。

发现问题:

首先,如果是这样的开始两个数组graph[0]={2,3},graph[1]={4,5},这种情况下如何确定1和0在那个分组内呢?因为没有办法确定,所以不能轻易给0和1分组。否则会在后续的判断中误认为是无法组成二分图的。

其次,如果是空的比如graph[0]={},那么0被分在哪一组都是无所谓的。

第三,可能存在两组不相连的图

在这里插入图片描述

这种情况下,第一个子图数之间的关系和第二个子图没有关系。可以独立计算。

改进,将遍历变为递归。

问题2:

由于已经知道所有会出现的数字,所以可以使用数组来代替hashset,下标表示位置,值表示属于哪一组。
在这里插入图片描述

int[] array;
public boolean isBipartite(int[][] graph) {


    array=new int[graph.length];

    for (int i=0;i<graph.length;i++){
        //对他进行分组,如果分组出现问题,返回false
        if (!each(graph,i )){
            return false;
        }
    }
    return true;
}
//遍历,输入数字i就可以把i和其所相连的分组
public boolean each(int[][] graph,int i){

    //如果i在组B中
    if (array[i]==2){
        //把和i相连的都放到A组
        for (int j=0;j<graph[i].length;j++){

            //如果已经在B组了,报错
            if (array[graph[i][j]]==2){
                return false;
            }
            //如果没有分组,对这个数进行递归分组
            else if (array[graph[i][j]]==0){
                array[graph[i][j]]=1;
                each(graph, graph[i][j]);
            }
            //如果这个数已经在B组了,直接跳过
        }

    }
    //如果在A组或者不存在,两组都不在,随便放到那一组中
    else
    {
        //放到A组
        array[i]=1;

        //把和i相连的都放到B组
        for (int j=0;j<graph[i].length;j++){

            //如果已经在A组了,报错
            if (array[graph[i][j]]==1){
                return false;
            }
            //如果没有分组,对这个数进行递归分组
            else if (array[graph[i][j]]==0){
                array[graph[i][j]]=2;
                each(graph, graph[i][j]);
            }
            //如果这个数已经在B组了,直接跳过
        }
    }

    return true;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值