LeetCode 990. 等式方程的可满足性之并查集和深度优先搜索解题思路

题目描述

给定一个由表示变量之间关系的字符串方程组成的数组,每个字符串方程 equations[i] 的长度为 4,并采用两种不同的形式之一:“a==b” 或  “a!=b”。在这里,a 和 b 是小写字母(不一定不同),表示单字母变量名。

只有当可以将整数分配给变量名,以便满足所有给定的方程时才返回  true,否则返回 false。

示例 1:
输入:[“a==b”,“b!=a”]
输出:false
解释:如果我们指定,a = 1 且 b = 1,那么可以满足第一个方程,但无法满足第二个方程。没有办法分配变量同时满足这两个方程。

示例 2:
输入:[“ba”,“ab”]
输出:true
解释:我们可以指定 a = 1 且 b = 1 以满足满足这两个方程。

示例 3:
输入:[“ab”,“bc”,“a==c”]
输出:true

示例 4:
输入:[“ab”,“b!=c”,“ca”]
输出:false

示例 5:
输入:[“cc”,“bd”,“x!=z”]
输出:true

提示:

  • 1 <= equations.length <= 500
  • equations [i].length == 4
  • equations[i][0] 和  equations[i][3]  是小写字母
  • equations[i][1] 要么是  ‘=’,要么是  ‘!’
  • equations[i][2]  是  ‘=’

题目链接:https://leetcode-cn.com/problems/satisfiability-of-equality-equations/

对象声明

/**
 * 待检查不等式
 */
class NonEquation {
    final char ch1;
    final char ch2;

    NonEquation(char ch1, char ch2) {
        this.ch1 = ch1;
        this.ch2 = ch2;
    }
}

解题思路

一、并查集

首先遍历所有的表达式,如果是等式则把两个变量指向同一个根,即把两个变量对应的集合进行合并,如果是不等式则把不等式放入待检查的队列中。当表达式遍历完成后,开始检查队列中的不等式,如果不等式的两个变量 ch1,ch2 有相同的根,即两个变量在同一个集合中,说明 ch1 == ch2,那么表达式 ch1 != ch2 就不成立,直接返回 false,如果检查完成,所有的不等式都成立,则返回 true。

public boolean equationsPossible(String[] equations) {
    Map<Character, Character> data = new HashMap<>();
    Map<Character, Integer> level = new HashMap<>();
    Queue<NonEquation> queue = new LinkedList<>();
    for (String equation : equations) {
        char ch1 = equation.charAt(0);
        char ch2 = equation.charAt(3);
        char symbol = equation.charAt(1);
        if (symbol == '=') {
            if (ch1 == ch2) {
                continue;
            }
            union(ch1, ch2, data, level);
        } else {
            if (ch1 == ch2) {
                return false;
            }
            queue.offer(new NonEquation(ch1, ch2));
        }
    }
    while (!queue.isEmpty()) {
        NonEquation nonEquation = queue.poll();
        char root1 = find(nonEquation.ch1, data);
        char root2 = find(nonEquation.ch2, data);
        if (root1 == root2) {
            return false;
        }
    }
    return true;
}

public void union(char ch1, char ch2, Map<Character, Character> data, Map<Character, Integer> level) {
    char root1 = find(ch1, data);
    char root2 = find(ch2, data);
    if (root1 == root2) {
        return;
    }
    int level1 = level.getOrDefault(root1, 0);
    int level2 = level.getOrDefault(root2, 0);
    if (level1 > level2) {
        data.put(root2, root1);
    } else if (level1 < level2) {
        data.put(root1, root2);
    } else {
        data.put(root1, root2);
        level.put(root2, level2 + 1);
    }
}

public char find(char ch, Map<Character, Character> data) {
    char value = ch;
    while (data.get(value) != null) {
        value = data.get(value);
    }
    return value;
}
二、深度优先搜索+回溯算法

首先定义一个邻接矩阵 matrix[26][26],保存顶点之间的连通性,然后开始遍历所有的表达式,如果是等式则认为两个变量之间是连通的,将 matrix[ch1][ch2]设置为 true,如果是不等式则把不等式放入待检查的队列中。当表达式遍历完成后,开始检查队列中的不等式,使用深度搜索去查找 ch1 和 ch2 之前是否存在一条路径,如果不等式的两个变量 ch1,ch2 之前存在一条路径,即 ch1 和 ch2 之间是连通的,则说明 ch1 == ch2,那么表达式 ch1 != ch2 就不成立,直接返回 false,如果检查完成,所有的不等式都成立,则返回 true。

public boolean equationsPossible(String[] equations) {
    boolean[][] matrix = new boolean[26][26];
    Queue<NonEquation> queue = new LinkedList<>();
    for (String equation : equations) {
        char ch1 = equation.charAt(0);
        char ch2 = equation.charAt(3);
        char symbol = equation.charAt(1);
        if (symbol == '=') {
            if (ch1 == ch2) {
                continue;
            }
            matrix[ch1 - 'a'][ch2 - 'a'] = true;
            matrix[ch2 - 'a'][ch1 - 'a'] = true;
        } else {
            if (ch1 == ch2) {
                return false;
            }
            queue.offer(new NonEquation(ch1, ch2));
        }
    }
    while (!queue.isEmpty()) {
        NonEquation node = queue.poll();
        boolean[][] visited = new boolean[matrix.length][matrix[0].length];
        boolean res = equationsPossible_dfs(matrix, node.ch1 - 'a', node.ch2 - 'a', visited);
        if (!res) {
            return false;
        }
    }
    return true;
}

public boolean equationsPossible_dfs(boolean[][] matrix, int i, int target, boolean[][] visited) {
    for (int k = 0; k < matrix[0].length; k++) {
        if (!matrix[i][k]) {
            continue;
        }
        if (visited[i][k] || visited[k][i]) {
            continue;
        }
        if (k == target) {
            return false;
        }
        visited[i][k] = true;
        boolean res = equationsPossible_dfs(matrix, k, target, visited);
        visited[i][k] = false;
        if (!res) {
            return false;
        }
    }
    return true;
}

视频讲解

  1. 在 YouTube 上查看请点击https://youtu.be/p0QnHcQBVK0
  2. 在 B 站上查看请点击https://www.bilibili.com/video/BV1Mt4y197wc
  3. 在西瓜视频上查看请点击https://www.ixigua.com/i6838141591039771140
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值