添加边使所有节点度数都为偶数

116 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第 30 天,点击查看活动详情

问题描述

给你一个有 n 个节点的 无向 图,节点编号为 1 到 n 。再给你整数 n 和一个二维整数数组 edges ,其中 edges[i] = [ai, bi] 表示节点 ai 和 bi 之间有一条边。图不一定连通。

你可以给图中添加 至多 两条额外的边(也可以一条边都不添加),使得图中没有重边也没有自环。

如果添加额外的边后,可以使得图中所有点的度数都是偶数,返回 true ,否则返回 false 。

点的度数是连接一个点的边的数目。

示例 1:

输入: n = 5, edges = [[1,2],[2,3],[3,4],[4,2],[1,4],[2,5]]
输出: true
解释: 上图展示了添加一条边的合法方案。
最终图中每个节点都连接偶数条边。

示例 2:

输入: n = 4, edges = [[1,2],[3,4]]
输出: true
解释: 上图展示了添加两条边的合法方案。

示例 3:

输入: n = 4, edges = [[1,2],[1,3],[1,4]]
输出: false
解释: 无法添加至多 2 条边得到一个符合要求的图。

提示:

  • 3 <= n <= 10^5
  • 2 <= edges.length <= 10^5
  • edges[i].length == 2
  • 1 <= ai, bi <= n
  • ai != bi
  • 图中不会有重边

思路分析

首先我们要先理解一下题目意思,题目会给我们一个整数 n 和一个二维整数数组 edges,其中 edges[i] = [ai, bi] 表示节点 ai 和 bi 之间有一条边,且图不一定连通。我们需要判断是否可以通过添加至多两条边来使得图中每个节点的度数都是偶数,并且图中不可以出现重边和自环。

首先我们可以先分析一下可能出现的情况:

  • 1、图中存在两个奇数度数的节点,并且两节点之间没有边

这种情况下,我们可以直接在两个节点之间加上一条边。

  • 2、图中存在两个奇数度数的节点,并且两节点之间存在边,但可以找到第三个度数为偶数的节点与两个节点均不存在边

这种情况下,我们可以将第三个节点分别和两个节点加上边。

  • 3、图中存在两个奇数度数的节点,并且两节点之间存在边,也不可以找到第三个度数为偶数的节点与两个节点均不存在边

这种情况下我们无法通过添加边使得所有节点的度数都为偶数。

  • 4、图中存在四个奇数度数的节点,并且四个节点可以分成两两一组,每组的两个节点之间没有边

这种情况下我们可以直接在每组两个节点之间加上一条边。

  • 5、图中存在四个奇数度数的节点,并且四个节点可以分成两两一组,一组的两个节点之间没有边,另一组可以找到第三个度数为偶数的节点与两个节点均不存在边

这种情况下我们需要添加三条边才可以使得所有节点的度数都为偶数。

  • 6、图中存在四个奇数度数的节点,并且四个节点可以分成两两一组,每组的两个节点之间存在边,每组都可以找到第三个度数为偶数的节点与两个节点均不存在边

这种情况下我们需要添加四条边才可以使得所有节点的度数都为偶数。

  • 7、图中存在四个奇数度数的节点,并且四个节点可以分成两两一组,每组的两个节点之间存在边,有一组不可以找到第三个度数为偶数的节点与两个节点均不存在边

这种情况下我们无法通过添加边使得所有节点的度数都为偶数。

  • 8、图中存在四个以上个奇数度数的节点

这种情况下我们无法通过添加边使得所有节点的度数都为偶数。

我们只需要分类讨论判断完以上的各种情况即可得出答案。

AC 代码

完整代码如下:

/**
 * @param {number} n
 * @param {number[][]} edges
 * @return {boolean}
 */
 var isPossible = function(n, edges) {
    const map = new Map();
    const set = new Set();
    for(let i = 0; i < edges.length; i++){
       map.set(edges[i][0],(map.get(edges[i][0]) || 0) + 1);
       map.set(edges[i][1],(map.get(edges[i][1]) || 0) + 1);
       if(edges[i][0] > edges[i][1]){
           set.add(edges[i][1] + '-' + edges[i][0]);
       }else{
           set.add(edges[i][0] + '-' + edges[i][1]);
       }
    }
    const arr = [];
    for(let i = 1; i <= n; i++){
        if(map.get(i) % 2 == 1) arr.push(i);
    }
    if(arr.length == 0) return true;
    if(arr.length > 4 || arr.length % 2 == 1) return false;
    const check = (a,b)=>{
        if(!set.has(a + '-' + b)){
            set.add(a + '-' + b);
            return 1;
        }
        for(let k = 1; k <= n; k++){
            if(arr.includes(k)) continue;
            const a1 = Math.min(k,a);
            const b1 = Math.max(k,a);
            const a2 = Math.min(k,b);
            const b2 = Math.max(k,b);
            if(!set.has(a1 + '-' + b1) && !set.has(a2 + '-' + b2)){
                set.add(a1 + '-' + b1);
                set.add(a2 + '-' + b2);
                return 2;
            }
        }
        return Infinity;
    };
    if(arr.length == 2){
        return check(arr[0],arr[1]) < 3;
    }
    const x1 = check(arr[0],arr[1]) + check(arr[2],arr[3]);
    const x2 = check(arr[0],arr[2]) + check(arr[1],arr[3]);
    const x3 = check(arr[0],arr[3]) + check(arr[1],arr[2]);
    return (x1 < 3 || x2 < 3 ||  x3 < 3);
};

说在后面

本人为算法业余爱好者,平时只是随着兴趣偶尔刷刷题,如果上面分享有错误的地方,欢迎指出,感激不尽。