Leetcode刷题 2021.01.13

Leetcode684 冗余连接

在本问题中, 树指的是一个连通且无环的无向图。

输入一个图,该图由一个有着N个节点 (节点值不重复1, 2, …, N) 的树及一条附加的边构成。附加的边的两个顶点包含在1到N中间,这条附加的边不属于树中已存在的边。

结果图是一个以边组成的二维数组。每一个边的元素是一对[u, v] ,满足 u < v,表示连接顶点u 和v的无向图的边。

返回一条可以删去的边,使得结果图是一个有着N个节点的树。如果有多个答案,则返回二维数组中最后出现的边。答案边 [u, v] 应满足相同的格式 u < v。

图论月,彳亍。又是并查集,如果上周做的话可能都无从下手,现在做就是并查集模板了。

class Solution {
    public int[] findRedundantConnection(int[][] edges) {
         if (edges == null || edges.length == 0) return new int[]{0, 0};
         //没什么好注释的,并查集模板题。。
         int n = edges.length + 1;
         UnionFind uf = new UnionFind(n);
         for(int i = 0; i < edges.length; i++){
             int x = edges[i][0], y = edges[i][1];
             if (!uf.union(x, y)){
                 return new int[]{x, y};
             }
         }
          return new int[]{0, 0};
    }

    class UnionFind{
        int[] parent;

        public UnionFind(int n){
            parent = new int[n];
            for(int i = 0; i < n; i++){
                parent[i] = i;
            }
        }

        private int find(int i){
            if(parent[i] == i){
                return parent[i];
            }
            return parent[i] = find(parent[i]);
        }

        private boolean union(int i, int j){
            int root1 = find(i);
            int root2 = find(j);
            if (root1 == root2) return false;
            parent[root1] = parent[root2];

            return true;
        }
    }
}

Leetcode210 元素和小于等于阈值的正方形的最大边长

现在你总共有 n 门课需要选,记为 0 到 n-1。

在选修某些课程之前需要一些先修课程。 例如,想要学习课程 0 ,你需要先完成课程 1 ,我们用一个匹配来表示他们: [0,1]

给定课程总量以及它们的先决条件,返回你为了学完所有课程所安排的学习顺序。

可能会有多个正确的顺序,你只要返回一种就可以了。如果不可能完成所有课程,返回一个空数组。

昨天的每日一题不会做,但是拓扑排序还是学了下。看了Liweiwei的题解,主要还是使用广度优先遍历,将入度为0的点一一入队即可。

class Solution {
    public int[] findOrder(int numCourses, int[][] prerequisites) {
        if (numCourses <= 0) return new int[0];
        //声明邻接表,用list数组表示
        List<Integer>[] adj = new ArrayList[numCourses];
        //初始化一下
        for(int i = 0; i < numCourses; i++){
            adj[i] = new ArrayList<>();
        }
        //每个结点的入度表
        int[] indegree = new int[numCourses];
        //如果有p[1]指向p[0]的边,就添加到邻接表,并且p[0]的入度加1.
        for(int[] p : prerequisites){
            adj[p[1]].add(p[0]);
            indegree[p[0]]++;
        }
        //结果数组
        int[] res = new int[numCourses];
        //广度优先使用队列
        Queue<Integer> queue = new LinkedList<>();
        //入度为0的点入队
        for(int i = 0; i < numCourses; i++){
            if (indegree[i] == 0){
                queue.offer(i);
            }
        }
        //结果个数
        int count = 0;
        while (!queue.isEmpty()){
        	//出队
            Integer temp = queue.poll();
            //放到结果集
            res[count++] = temp;
			//遍历出队元素的邻接表,把这些点的入度都减一
            for(int ele : adj[temp]){
                indegree[ele]--;
                //如果入度为0,入队
                if (indegree[ele] == 0){
                    queue.offer(ele);
                }
            }
        }
        //count == numCourses说明有结果
        if (count == numCourses){
            return res;
        }
		//没有结果返回空数组
        return new int[0];
    }
}

Leetcode1669 合并两个链表

给你两个链表 list1 和 list2 ,它们包含的元素分别为 n 个和 m 个。

请你将 list1 中第 a 个节点到第 b 个节点删除,并将list2 接在被删除节点的位置。

链表题还是比较简单的吧,无非考虑边界,还有index位置。这种交换顺序的题目,不行就多用几个辅助结点。这题好像有一定的特殊性,边界问题不需要考虑很多。

class Solution {
    public ListNode mergeInBetween(ListNode list1, int a, int b, ListNode list2) {
    	//伪节点,链表题的常见套路了
        ListNode dummyHead = new ListNode(0);
        dummyHead.next = list1;
        ListNode cur = dummyHead;
        ListNode prevHead = null;
        ListNode prevTail = null;
        //先找a的位置的前一个结点,和b结点的后一个位置
        for(int i = 0; i < b + 2; i++){
            if (i == a) prevHead = cur;
            cur = cur.next;
        }
        prevTail = cur;
        //再找list的尾结点
        ListNode cur2 = list2, prev = null;
        while (cur2 != null){
            prev = cur2;
            cur2 = cur2.next;
        }
        //两个链上就行
        prevHead.next = list2;
        prev.next = prevTail;
        return dummyHead.next;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值