Leetcode刷题 2021.03.24

Leetcode1101 彼此熟识的最早时间

在一个社交圈子当中,有 N 个人。每个人都有一个从 0 到 N-1 唯一的 id 编号。
我们有一份日志列表 logs,其中每条记录都包含一个非负整数的时间戳,以及分属两个人的不同 id,logs[i] = [timestamp, id_A, id_B]。
每条日志标识出两个人成为好友的时间,友谊是相互的:如果 A 和 B 是好友,那么 B 和 A 也是好友。
如果 A 是 B 的好友,或者 A 是 B 的好友的好友,那么就可以认为 A 也与 B 熟识。
返回圈子里所有人之间都熟识的最早时间。如果找不到最早时间,就返回 -1 。

再继续等面试结果中。。这题是比较容易想到并查集的,因为好友具有传递性,就能用并查集合并好友。另外为了获得最早的时间,可以先贪心的对时间进行排序,如果好友圈子为1了,就返回该时间就行了。

class Solution {
    public int earliestAcq(int[][] logs, int N) {
    	//先按照时间从小到大进行排序
        Arrays.sort(logs, (x, y) -> (x[0] - y[0]));
        UnionFind uf = new UnionFind(N);
        for(int[] log :logs){
        	//合并两个好友
            uf.union(log[1], log[2]);
            //如果只有一个好友圈子,就返回该时间
            if (uf.size == 1){
                return log[0];
            }
        }
        //否则返回-1
        return -1;
    }

    class UnionFind{
        int[] parent;
        int size;
        public UnionFind(int n){
            this.size = n;
            parent = new int[n];

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

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

        public void union(int i, int j){
            int root1 = find(i);
            int root2 = find(j);
            if (root1 == root2) return;
            parent[root1] = root2;
            size--;
        }
    }
}

Leetcode1100 长度为 K 的无重复字符子串

给你一个字符串 S,找出所有长度为 K 且不含重复字符的子串,请你返回全部满足要求的子串的 数目。

长度为k,又是某某子串,那一般就是滑动窗口解法了。也是比较经典的滑动窗口题,先增大右窗口,如果右窗口不符合某一条件时,缩小左窗口。再判断求解就行了。


class Solution {
    public int numKLenSubstrNoRepeats(String S, int K) {
        char[] arr = S.toCharArray();
        int res = 0, i = 0, n = arr.length;
        //都是小写英文字母,可以用数组代替map
        int[] map = new int[26];
        for(int j = 0; j < n; j++){
        	//先增大右窗口
            map[arr[j] - 'a']++;
            //如果右窗口有重复,就缩小左窗口
            while (map[arr[j] - 'a'] > 1){
                map[arr[i] - 'a']--;
                i++;
            }
            //如果子串长度为K,就res++
            if (j - i + 1 == K){
                res++;
                map[arr[i] - 'a']--;
                i++;
            }
        }
        return res;
    }
}

Leetcode678 有效的括号字符串

给你二叉搜索树的根节点 root ,同时给定最小边界low 和最大边界 high。通过修剪二叉搜索树,使得所有节点的值在[low, high]中。修剪树不应该改变保留在树中的元素的相对结构(即,如果没有被移除,原有的父代子代关系都应当保留)。 可以证明,存在唯一的答案。

所以结果应当返回修剪好的二叉搜索树的新的根节点。注意,根节点可能会根据给定的边界发生改变。

这题写了个超级复杂的递归加迭代,时间复杂度其实是一样的,就是代码写的实在太冗余了。看了官方题解觉得写的真的很简洁。。

class Solution {
    public TreeNode trimBST(TreeNode root, int low, int high) {
        if (root == null) return root;
        helper(root, low, high);
        //对root要做相同的处理
        while (root.left != null && root.left.val < low){
            TreeNode temp = root.left.right;
            root.left = temp;
        }
        while (root.left != null && root.left.val > high){
            root.left = root.left.left;
        }
        while (root.right != null && root.right.val > high){
            TreeNode temp = root.right.left;
            root.right = temp;
        }
        while (root.right != null && root.right.val < low){
            root.right = root.right.right;
        }
        if (root.val < low){
            return root.right;
        }else if (root.val > high){
            return root.left;
        }
        return root;
    }

    private void helper(TreeNode root, int low, int high){
        if (root == null) return;
        //如果左子树的值小于low,那就让root指向左树的右子树
        while (root.left != null && root.left.val < low){
            TreeNode temp = root.left.right;
            root.left = temp;
        }
        //如果左子树的值大于high,就让root指向左子树的左子树,下面同理,然后递归就行了
        while (root.left != null && root.left.val > high){
            root.left = root.left.left;
        }
        while (root.right != null && root.right.val > high){
            TreeNode temp = root.right.left;
            root.right = temp;
        }
        while (root.right != null && root.right.val < low){
            root.right = root.right.right;
        }

        helper(root.left, low, high);
        helper(root.right, low, high);
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值