leecode - 2392. 给定条件下构造矩阵

题目地址

https://leetcode.cn/problems/build-a-matrix-with-conditions/

题目描述

给你一个 正 整数 k ,同时给你:

一个大小为 n 的二维整数数组 rowConditions ,其中 rowConditions[i] = [abovei, belowi] 和
一个大小为 m 的二维整数数组 colConditions ,其中 colConditions[i] = [lefti, righti] 。
两个数组里的整数都是 1 到 k 之间的数字。

你需要构造一个 k x k 的矩阵,1 到 k 每个数字需要 恰好出现一次 。剩余的数字都是 0 。

矩阵还需要满足以下条件:

对于所有 0 到 n - 1 之间的下标 i ,数字 abovei 所在的 行 必须在数字 belowi 所在行的上面。
对于所有 0 到 m - 1 之间的下标 i ,数字 lefti 所在的 列 必须在数字 righti 所在列的左边。
返回满足上述要求的 任意 矩阵。如果不存在答案,返回一个空的矩阵。

 

题目分析

1.根据限制条件,如果在rowConditions,colConditions 中存在[1,2],[2,1] 这种环形依赖的关系,则数组不存在,根据rowConditions数组的描述,可以提炼出属于有向图是否优化你的问题

2.由于规定了"数字 abovei 所在的 行 必须在数字 belowi 所在行的上面" , 说明存在排序关系,并且最大的数应该在第0行

3.综合以上,提取出拓扑排序问题

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;

class Solution2 {
    public int[][] buildMatrix(int k, int[][] rowConditions, int[][] colConditions) {
        // 行排序
        int[] rows = sort(k, rowConditions);
        if (rows.length == 0) {
            return new int[0][0];
        }

        // 列排序
        int[] cols = sort(k, colConditions);
        if (cols.length == 0) {
            return new int[0][0];
        }

        // 处理结果
        return build(k, rows, cols);
    }

    private int[] sort(int k, int[][] cs) {
        // 拓扑排序
        int[] ans = new int[k + 1];
        int idx = 0;

        // 这里有坑,只能用邻接表,不能用邻接矩阵
        // 测试用例中有重复的边,比如:[[1,2],[7,3],[4,3],[5,8],[7,8],[8,2],[5,8],[3,2],[1,3],[7,6],[4,3],[7,4],[4,8],[7,3],[7,5]]
        // 用邻接矩阵会导致入度多算而边没有多算
        List<Integer>[] g = new List[k + 1];
        for (int i = 1; i <= k; i++) {
            g[i] = new ArrayList<>();
        }
        int[] indeg = new int[k + 1];
        for (int[] c : cs) {
            g[c[0]].add(c[1]);
            indeg[c[1]]++;
        }

        Queue<Integer> queue = new LinkedList<>();
        //由于indeg[i] == 0 表示,入度为0, 这种点没有依赖顺序,所以从小到大遍历,还是从大到小都是可以的,随机也是可以的

        for (int i = 1; i <= k; i++) {
            if (indeg[i] == 0) {
                queue.offer(i);
            }
        }

        while (!queue.isEmpty()) {
            int node = queue.poll();
            // 存储的是哪个数字放在哪一行,而不是哪行存储哪个数字
            //将拓扑排序的结果看成每个数字的行号即可,最大的点应该在最上边行,并且最大的点在栈的栈底,通过               //这个关系,维护了最大点所在的行
            ans[node] = idx++;
            
            //删除当前点对应边的入度关系
            for (int next : g[node]) {
                //如果删除完成后,变成入度为0的点
                if (--indeg[next] == 0) {
                    queue.offer(next);
                }
            }
        }

        // 有环时idx肯定到不了k
        // 如果有环,idx一定小于k,因为一定有对应的点的没有加入栈里
        if (idx != k) {
            return new int[0];
        }
        //ans维护了一个最大数所在的行的关系, a[i]的值表示所在二维数组所在的行
        return ans;
    }

    private int[][] build(int k, int[] rows, int[] cols) {
        int[][] ans = new int[k][k];

        for (int i = 1; i <= k; i++) {
            // i存储在哪行哪列
            // 通过rows[i] 获取i所在的行 , 通过cols[i]获取i所在的列,确定二维数组中i的位置

            ans[rows[i]][cols[i]] = i;
        }

        return ans;
    }
}

/**
 * 作者:tong-zhu
 * 链接:https://leetcode.cn/problems/build-a-matrix-with-conditions/solution/by-tong-zhu-4uv6/
 * 来源:力扣(LeetCode)
 * 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
 */

参考资料

https://zhuanlan.zhihu.com/p/135094687

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值