Leetcode刷题 2021.01.28

Leetcode724 寻找数组的中心索引

给你一个整数数组 nums,请编写一个能够返回数组 “中心索引” 的方法。

数组 中心索引 是数组的一个索引,其左侧所有元素相加的和等于右侧所有元素相加的和。

如果数组不存在中心索引,返回 -1 。如果数组有多个中心索引,应该返回最靠近左边的那一个

注意:中心索引可能出现在数组的两端

简单题就是会做的一眼就能看出来。这题知道前缀和的技巧的话应该就没问题了,之前看到字节的一道面试题就是这题的二维版本而已。话说面试的时候就算一眼就能看出来或者刷过题,还是装下样子,和面试官讨论讨论吧。

class Solution {
    public int pivotIndex(int[] nums) {
        int n = nums.length;
        if (n == 0) return -1;
        int[] help = new int[n];
        int sum = 0;
        //朴素版前缀和,构建辅助数组,也可以不用,只算一次总和。
        for(int i = 0; i < n; i++){
            help[i] = sum + nums[i];
            sum = help[i];
        }
        for(int i = 0; i < n; i++){
            if (help[i] - nums[i] == help[n - 1] - help[i]){
                return i;
            }
        }

        return -1;
    }
}

Leetcode802 找到最终的安全状态

在有向图中, 我们从某个节点和每个转向处开始, 沿着图的有向边走。 如果我们到达的节点是终点 (即它没有连出的有向边), 我们停止。

现在, 如果我们最后能走到终点,那么我们的起始节点是最终安全的。 更具体地说, 存在一个自然数 K, 无论选择从哪里开始行走, 我们走了不到 K 步后必能停止在一个终点。

哪些节点最终是安全的? 结果返回一个有序的数组。

该有向图有 N 个节点,标签为 0, 1, …, N-1, 其中 N 是 graph 的节点数. 图以以下的形式给出: graph[i] 是节点 j 的一个列表,满足 (i, j) 是图的一条有向边。

仔细观察的话其实就能发现就是检查有向图是否有环,那就是拓扑排序了。不过这题要注意的是构建邻接表的时候要反过来,有向图的话最先想到的应该就是拓扑排序了吧。

class Solution {
    List<Integer> res = new ArrayList<>();
    public List<Integer> eventualSafeNodes(int[][] graph) {
        if (graph.length == 0) return res;
        int n = graph.length;
        //邻接表
        List<List<Integer>> edge = new ArrayList<>();
        //BFS用队列
        Queue<Integer> queue = new LinkedList<>();
        //记录入度
        int[] indegree = new int[n];

        for(int i = 0; i < n; i++){
            edge.add(new ArrayList<>());
        }
        //反向构建邻接表
        for(int i = 0; i < n; i++){
            for(int ele : graph[i]){
                edge.get(ele).add(i);
                indegree[i]++;
            }
            //入度为0加入队列
            if (indegree[i] == 0) queue.offer(i);
        }

        while (!queue.isEmpty()){
            int temp = queue.poll();
            //把相邻点的入度减一,如果入度为0就入队
            for(int ele : edge.get(temp)){
                indegree[ele]--;
                if (indegree[ele] == 0) queue.offer(ele);
            }
        }
        //因为要返回有序的数组,所以再从头到尾遍历一次
        for(int i = 0; i < n; i++){
            if (indegree[i] == 0) res.add(i);
        }

        return res;
    }

}

Leetcode886 可能的二分法

给定一组 N 人(编号为 1, 2, …, N), 我们想把每个人分进任意大小的两组。

每个人都可能不喜欢其他人,那么他们不应该属于同一组。

形式上,如果 dislikes[i] = [a, b],表示不允许将编号为 a 和 b 的人归入同一组。

当可以用这种方法将所有人分进两组时,返回 true;否则返回 false。

一开始以为就是判断无向图是否有环,但是不是这样的。还是应该对点进行分类,参考了下题解,用最近做的很多的并查集来做。对于每个要分到不同类的两个点x, y,都让(x, x +n), (y, y + n)进行合并。如果后面出现矛盾的话就返回false了,比较有技巧的一个解法。

class Solution {
     public boolean possibleBipartition(int N, int[][] dislikes) {
     	//开一个2n大小的并查集
         UnionFind uf = new UnionFind(2 * N);
         //让序号从0开始,并且对于不同类的两个点,都和(x, x +n), (y, y + n)进行合并
         for(int[] ele : dislikes){
             ele[0]--;
             ele[1]--;
             if (uf.find(ele[0]) == uf.find(ele[1])) return false;
             uf.uinion(ele[0], ele[1] + N);
             uf.uinion(ele[0] + N, ele[1]);
         }
		
		//没有矛盾就返回true了。
         return true;
     }

    class UnionFind{
        int[] parent;

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

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

            return parent[i] = find(parent[i]);
        }

        public void uinion(int i, int j){
            int root1 = find(i);
            int root2 = find(j);
            if (root1 == root2) return;
            parent[root1] = root2;
        }
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值