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);
}
}