Leetcode刷题 2021.01.23
Leetcode1319 连通网络的操作次数
用以太网线缆将 n 台计算机连接成一个网络,计算机的编号从 0 到 n-1。线缆用 connections 表示,其中 connections[i] = [a, b] 连接了计算机 a 和 b。
网络中的任何一台计算机都可以通过网络直接或者间接访问同一个网络中其他任意一台计算机。
给你这个计算机网络的初始布线 connections,你可以拔开任意两台直连计算机之间的线缆,并用它连接一对未直连的计算机。请你计算并返回使所有计算机都连通所需的最少操作次数。如果不可能,则返回 -1 。
已经摸清leetcode套路了,明天的每日一题应该是困难的并查集,然后是一道随便的简单题,然后又是中等并查集。话说并查集做了这么多,大题能掌握了。问题就是怎么能想到用并查集,要是面试的时候想不出来,就问问面试官吧。
这题也是并查集模板了,合并完以后查看有多少个连通分量即可。
class Solution {
public int makeConnected(int n, int[][] connections) {
// n 个节点相互连通至少需要n-1条线
if (connections.length < n - 1) {
return -1;
}
UnionFind uf = new UnionFind(n);
for(int[] ele : connections){
int x = ele[0], y = ele[1];
uf.union(x, y);
}
int count = 0;
//查看有几个连通分量
for(int i = 0; i < n; i++){
if (uf.parent[i] == i){
count++;
}
}
return count - 1;
}
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 i;
}
return parent[i] = find(parent[i]);
}
private void union(int i, int j){
int root1 = find(i);
int root2 = find(j);
if (root1 == root2) return ;
parent[root1] = root2;
}
}
}
Leetcode117 填充每个节点的下一个右侧节点指针 II
给定一个二叉树
**struct Node {
int val;
Node *left;
Node right;
Node next;
}
填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL。
初始状态下,所有 next 指针都被设置为 NULL。
这题一开始的想法就是BFS,下面就是最正常的BFS代码,但是题目要求常数的空间复杂度,想不出来,看了下题解。其实编码也不难,问题就是怎么想到这种解法。还是要多练啊。
public Node connect(Node root) {
if (root == null) return root;
Queue<Node> queue = new LinkedList<>();
queue.offer(root);
//正常BFS
while (!queue.isEmpty()){
int n = queue.size();
Node prev = null;
for(int i = 0; i < n; i++){
Node temp = queue.poll();
if (prev != null) prev.next = temp;
if (temp.left != null) queue.offer(temp.left);
if (temp.right != null) queue.offer(temp.right);
prev = temp;
}
}
return root;
}
public Node connect(Node root) {
if (root == null) return root;
Node cur = root;
//把每一层看作是一个链表,每一次对子树进行连接
while (cur != null){
Node dummyHead = new Node(0);
Node prev = dummyHead;
while (cur != null){
//如果左子节点不为null,就对左子节点进行串联
if (cur.left != null){
prev.next = cur.left;
prev = prev.next;
}
//右子节点同理
if (cur.right != null){
prev.next = cur.right;
prev = prev.next;
}
cur = cur.next;
}
cur = dummyHead.next;
}
return root;
}
Leetcode1497 检查数组对是否可以被 k 整除
给你一个整数数组 arr 和一个整数 k ,其中数组长度是偶数,值为 n 。
现在需要把数组恰好分成 n / 2 对,以使每对数字的和都能够被 k 整除。
如果存在这样的分法,请返回 True ;否则,返回 False 。
这题做的好差,只能击败5%/(ㄒoㄒ)/~~。看到题解里面各种奇淫巧计,就是想不到。我的思路比较直接,因为有负数,所以如果有相反数的数对,就让它们先合并,加起来为0,然后消除它们(为什么可以这样可以想一想)。然后再遍历哈希表,如果!map.get(key).equals(map.get(k - key)),就返回false了。这里也要分正数和负数讨论
class Solution {
public boolean canArrange(int[] arr, int k) {
//HashMap记录余数
Map<Integer, Integer> map = new HashMap<>();
for(int i = 0; i < arr.length; i++){
int temp = (int)((long) arr[i] % k);
map.put(temp, map.getOrDefault(temp, 0) + 1);
//如果有相反的余数,就先加起来,让它们消除
if (map.containsKey(-temp) && map.get(-temp) > 0){
map.put(temp, map.get(temp) - 1);
map.put(-temp, map.get(-temp) - 1);
}
}
//余数为0的一定要是偶数才行
if(map.getOrDefault(0, 0) % 2 == 1){
return false;
}
//遍历map,看看如果是正数!map.get(key).equals(map.get(k - key))
//如果是偶数,!map.get(key).equals(map.get(-k - key))
for(Integer key : map.keySet()){
if (map.get(key) != 0){
if (key > 0){
if (!map.get(key).equals(map.get(k - key))){
return false;
}
}else{
if (!map.get(key).equals(map.get(-k - key))){
return false;
}
}
}
}
return true;
}
}