diff --git a/src/main/java/leetcode/medium/LeetCode_0743_NetworkDelayTime.java b/src/main/java/leetcode/medium/LeetCode_0743_NetworkDelayTime.java index b572186582692fcbd07fe3bf718b3b0deb410c1d..01878cadcaab64d276d4691524e3af58128d4fab 100644 --- a/src/main/java/leetcode/medium/LeetCode_0743_NetworkDelayTime.java +++ b/src/main/java/leetcode/medium/LeetCode_0743_NetworkDelayTime.java @@ -1,276 +1,265 @@ -//There are N network nodes, labelled 1 to N. -// -// Given times, a list of travel times as directed edges times[i] = (u, v, w), -// where u is the source node, v is the target node, -// and w is the time it takes for a signal to travel from source to target. -// -// Now, we send a signal from a certain node K. How long will it take for all nodes to receive the signal? -// If it is impossible, return -1. +// 有 n 个网络节点,标记为 1 到 n。 +// 给你一个列表 times,表示信号经过 有向 边的传递时间。 times[i] = (ui, vi, wi),其中 ui 是源节点,vi 是目标节点, wi +// 是一个信号从源节点传递到目标节点的时间。 +// 现在,从某个节点 K 发出一个信号。需要多久才能使所有节点都收到信号?如果不能使所有节点收到信号,返回 -1 。 package leetcode.medium; - import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.Map; - +// https://leetcode.cn/problems/network-delay-time/ +// 笔记: public class LeetCode_0743_NetworkDelayTime { - public static void main(String[] args) { - int[][] times = new int[][]{{1, 2, 1}, {2, 3, 2}, {1, 3, 1}}; - int N = 3; - int K = 2; - System.out.println(networkDelayTime(times, N, K)); + public static int networkDelayTime(int[][] times, int N, int K) { + // 转换成图结构 + Graph graph = generate(times); + Node from = null; + // 找到开始节点 + for (Node n : graph.nodes.values()) { + if (n.value == K) { + from = n; + } } - - public static int networkDelayTime(int[][] times, int N, int K) { - Graph graph = generate(times); - Node from = null; - for (Node n : graph.nodes.values()) { - if (n.value == K) { - from = n; - } - } - HashMap map = dijkstra2(from, N); - int sum = -1; - - for (Map.Entry entry : map.entrySet()) { - if (entry.getValue() == 0) { - N--; - continue; - } - N--; - if (entry.getValue() == Integer.MAX_VALUE) { - return -1; - } else { - sum = Math.max(entry.getValue(), sum); - } - } - // 防止出现环的形状 - // int[][] times = new int[][]{{1, 2, 1}, {2, 3, 2}, {1, 3, 1}}; - // int N = 3; - // int K = 2; - if (N != 0) { - return -1; - } - return sum; + HashMap map = dijkstra2(from, N); + int sum = -1; + for (Map.Entry entry : map.entrySet()) { + if (entry.getValue() == 0) { + N--; + continue; + } + N--; + if (entry.getValue() == Integer.MAX_VALUE) { + return -1; + } else { + sum = Math.max(entry.getValue(), sum); + } } - - public static Graph generate(int[][] times) { - Graph graph = new Graph(); - for (int[] time : times) { - int from = time[0]; - int to = time[1]; - int weight = time[2]; - if (!graph.nodes.containsKey(from)) { - graph.nodes.put(from, new Node(from)); - } - if (!graph.nodes.containsKey(to)) { - graph.nodes.put(to, new Node(to)); - } - Node fromNode = graph.nodes.get(from); - Node toNode = graph.nodes.get(to); - Edge fromToEdge = new Edge(weight, fromNode, toNode); - //Edge toFromEdge = new Edge(weight, toNode, fromNode); - fromNode.nexts.add(toNode); - fromNode.out++; - //fromNode.in++; - //toNode.out++; - toNode.in++; - fromNode.edges.add(fromToEdge); - //toNode.edges.add(toFromEdge); - graph.edges.add(fromToEdge); - //graph.edges.add(toFromEdge); - } - - return graph; + // 防止出现环的形状 + // int[][] times = new int[][]{{1, 2, 1}, {2, 3, 2}, {1, 3, 1}}; + // int N = 3; + // int K = 2; + if (N != 0) { + return -1; + } + return sum; + } + // 二维数组转换成自己熟悉的图结构 + public static Graph generate(int[][] times) { + Graph graph = new Graph(); + for (int[] time : times) { + int from = time[0]; + int to = time[1]; + int weight = time[2]; + if (!graph.nodes.containsKey(from)) { + graph.nodes.put(from, new Node(from)); + } + if (!graph.nodes.containsKey(to)) { + graph.nodes.put(to, new Node(to)); + } + Node fromNode = graph.nodes.get(from); + Node toNode = graph.nodes.get(to); + Edge fromToEdge = new Edge(weight, fromNode, toNode); + // Edge toFromEdge = new Edge(weight, toNode, fromNode); + fromNode.nexts.add(toNode); + fromNode.out++; + // fromNode.in++; + // toNode.out++; + toNode.in++; + fromNode.edges.add(fromToEdge); + // toNode.edges.add(toFromEdge); + graph.edges.add(fromToEdge); + // graph.edges.add(toFromEdge); } - public static class Graph { - public HashMap nodes; - public HashSet edges; + return graph; + } - public Graph() { - nodes = new HashMap<>(); - edges = new HashSet<>(); - } + public static class Graph { + public HashMap nodes; + public HashSet edges; + + public Graph() { + nodes = new HashMap<>(); + edges = new HashSet<>(); } + } - public static class Edge { - public int weight; - public Node from; - public Node to; + public static class Edge { + public int weight; + public Node from; + public Node to; - public Edge(int weight, Node from, Node to) { - this.weight = weight; - this.from = from; - this.to = to; - } + public Edge(int weight, Node from, Node to) { + this.weight = weight; + this.from = from; + this.to = to; } + } - public static class Node { - public int value; - public int in; - public int out; - public ArrayList nexts; - public ArrayList edges; + public static class Node { + public int value; + public int in; + public int out; + public ArrayList nexts; + public ArrayList edges; - public Node(int value) { - this.value = value; - in = 0; - out = 0; - nexts = new ArrayList<>(); - edges = new ArrayList<>(); - } + public Node(int value) { + this.value = value; + in = 0; + out = 0; + nexts = new ArrayList<>(); + edges = new ArrayList<>(); } + } - public static HashMap dijkstra(Node from) { - HashMap distanceMap = new HashMap<>(); - distanceMap.put(from, 0); - HashSet selectedNodes = new HashSet<>(); - Node minNode = getMinNode(distanceMap, selectedNodes); - while (minNode != null) { - int distance = distanceMap.get(minNode); - for (Edge neighbor : minNode.edges) { - Node to = neighbor.to; - if (!distanceMap.containsKey(to)) { - distanceMap.put(to, distance + neighbor.weight); - } else { - distanceMap.put(to, Math.min(distance + neighbor.weight, distanceMap.get(to))); - } - } - selectedNodes.add(minNode); - minNode = getMinNode(distanceMap, selectedNodes); + public static HashMap dijkstra(Node from) { + HashMap distanceMap = new HashMap<>(); + distanceMap.put(from, 0); + HashSet selectedNodes = new HashSet<>(); + Node minNode = getMinNode(distanceMap, selectedNodes); + while (minNode != null) { + int distance = distanceMap.get(minNode); + for (Edge neighbor : minNode.edges) { + Node to = neighbor.to; + if (!distanceMap.containsKey(to)) { + distanceMap.put(to, distance + neighbor.weight); + } else { + distanceMap.put(to, Math.min(distance + neighbor.weight, distanceMap.get(to))); } - return distanceMap; + } + selectedNodes.add(minNode); + minNode = getMinNode(distanceMap, selectedNodes); } + return distanceMap; + } - public static Node getMinNode(HashMap distanceMap, HashSet selectedNodes) { - int minDistance = Integer.MAX_VALUE; - Node minNode = null; - for (Map.Entry entry : distanceMap.entrySet()) { - Node n = entry.getKey(); - int distance = entry.getValue(); - if (!selectedNodes.contains(n) && distance < minDistance) { - minDistance = distance; - minNode = n; - } - } - return minNode; + public static Node getMinNode(HashMap distanceMap, HashSet selectedNodes) { + int minDistance = Integer.MAX_VALUE; + Node minNode = null; + for (Map.Entry entry : distanceMap.entrySet()) { + Node n = entry.getKey(); + int distance = entry.getValue(); + if (!selectedNodes.contains(n) && distance < minDistance) { + minDistance = distance; + minNode = n; + } } + return minNode; + } - public static class NodeRecord { - public Node node; - public int distance; + public static class NodeRecord { + public Node node; + public int distance; - public NodeRecord(Node node, int distance) { - this.node = node; - this.distance = distance; - } + public NodeRecord(Node node, int distance) { + this.node = node; + this.distance = distance; } + } - public static class NodeHeap { - private Node[] nodes; // 实际的堆结构 - // key 某一个node, value 上面堆中的位置 - private HashMap heapIndexMap; - // key 某一个节点, value 从源节点出发到该节点的目前最小距离 - private HashMap distanceMap; - private int size; // 堆上有多少个点 + public static class NodeHeap { + private Node[] nodes; // 实际的堆结构 + // key 某一个node, value 上面堆中的位置 + private HashMap heapIndexMap; + // key 某一个节点, value 从源节点出发到该节点的目前最小距离 + private HashMap distanceMap; + private int size; // 堆上有多少个点 - public NodeHeap(int size) { - nodes = new Node[size]; - heapIndexMap = new HashMap<>(); - distanceMap = new HashMap<>(); - size = 0; - } + public NodeHeap(int size) { + nodes = new Node[size]; + heapIndexMap = new HashMap<>(); + distanceMap = new HashMap<>(); + } - public boolean isEmpty() { - return size == 0; - } + public boolean isEmpty() { + return size == 0; + } - // 有一个点叫node,现在发现了一个从源节点出发到达node的距离为distance - // 判断要不要更新,如果需要的话,就更新 - public void addOrUpdateOrIgnore(Node node, int distance) { - if (inHeap(node)) { - distanceMap.put(node, Math.min(distanceMap.get(node), distance)); - insertHeapify(node, heapIndexMap.get(node)); - } - if (!isEntered(node)) { - nodes[size] = node; - heapIndexMap.put(node, size); - distanceMap.put(node, distance); - insertHeapify(node, size++); - } - } + // 有一个点叫node,现在发现了一个从源节点出发到达node的距离为distance + // 判断要不要更新,如果需要的话,就更新 + public void addOrUpdateOrIgnore(Node node, int distance) { + if (inHeap(node)) { + distanceMap.put(node, Math.min(distanceMap.get(node), distance)); + insertHeapify(node, heapIndexMap.get(node)); + } + if (!isEntered(node)) { + nodes[size] = node; + heapIndexMap.put(node, size); + distanceMap.put(node, distance); + insertHeapify(node, size++); + } + } - public NodeRecord pop() { - NodeRecord nodeRecord = new NodeRecord(nodes[0], distanceMap.get(nodes[0])); - swap(0, size - 1); - heapIndexMap.put(nodes[size - 1], -1); - distanceMap.remove(nodes[size - 1]); - // free C++同学还要把原本堆顶节点析构,对java同学不必 - nodes[size - 1] = null; - heapify(0, --size); - return nodeRecord; - } + public NodeRecord pop() { + NodeRecord nodeRecord = new NodeRecord(nodes[0], distanceMap.get(nodes[0])); + swap(0, size - 1); + heapIndexMap.put(nodes[size - 1], -1); + distanceMap.remove(nodes[size - 1]); + // free C++同学还要把原本堆顶节点析构,对java同学不必 + nodes[size - 1] = null; + heapify(0, --size); + return nodeRecord; + } - private void insertHeapify(Node node, int index) { - while (distanceMap.get(nodes[index]) - < distanceMap.get(nodes[(index - 1) / 2])) { - swap(index, (index - 1) / 2); - index = (index - 1) / 2; - } - } + private void insertHeapify(Node node, int index) { + while (distanceMap.get(nodes[index]) < distanceMap.get(nodes[(index - 1) / 2])) { + swap(index, (index - 1) / 2); + index = (index - 1) / 2; + } + } - private void heapify(int index, int size) { - int left = index * 2 + 1; - while (left < size) { - int smallest = left + 1 < size && distanceMap.get(nodes[left + 1]) < distanceMap.get(nodes[left]) - ? left + 1 - : left; - smallest = distanceMap.get(nodes[smallest]) - < distanceMap.get(nodes[index]) ? smallest : index; - if (smallest == index) { - break; - } - swap(smallest, index); - index = smallest; - left = index * 2 + 1; - } + private void heapify(int index, int size) { + int left = index * 2 + 1; + while (left < size) { + int smallest = + left + 1 < size && distanceMap.get(nodes[left + 1]) < distanceMap.get(nodes[left]) + ? left + 1 + : left; + smallest = + distanceMap.get(nodes[smallest]) < distanceMap.get(nodes[index]) ? smallest : index; + if (smallest == index) { + break; } + swap(smallest, index); + index = smallest; + left = index * 2 + 1; + } + } - private boolean isEntered(Node node) { - return heapIndexMap.containsKey(node); - } + private boolean isEntered(Node node) { + return heapIndexMap.containsKey(node); + } - private boolean inHeap(Node node) { - return isEntered(node) && heapIndexMap.get(node) != -1; - } + private boolean inHeap(Node node) { + return isEntered(node) && heapIndexMap.get(node) != -1; + } - private void swap(int index1, int index2) { - heapIndexMap.put(nodes[index1], index2); - heapIndexMap.put(nodes[index2], index1); - Node tmp = nodes[index1]; - nodes[index1] = nodes[index2]; - nodes[index2] = tmp; - } + private void swap(int index1, int index2) { + heapIndexMap.put(nodes[index1], index2); + heapIndexMap.put(nodes[index2], index1); + Node tmp = nodes[index1]; + nodes[index1] = nodes[index2]; + nodes[index2] = tmp; } + } - // 改进后的dijkstra算法 - // 从head出发,所有head能到达的节点,生成到达每个节点的最小路径记录并返回 - public static HashMap dijkstra2(Node head, int size) { - NodeHeap nodeHeap = new NodeHeap(size); - nodeHeap.addOrUpdateOrIgnore(head, 0); - HashMap result = new HashMap<>(); - while (!nodeHeap.isEmpty()) { - NodeRecord record = nodeHeap.pop(); - Node cur = record.node; - int distance = record.distance; - for (Edge edge : cur.edges) { - nodeHeap.addOrUpdateOrIgnore(edge.to, edge.weight + distance); - } - result.put(cur, distance); - } - return result; + // 改进后的dijkstra算法 + // 从head出发,所有head能到达的节点,生成到达每个节点的最小路径记录并返回 + public static HashMap dijkstra2(Node head, int size) { + NodeHeap nodeHeap = new NodeHeap(size); + nodeHeap.addOrUpdateOrIgnore(head, 0); + HashMap result = new HashMap<>(); + while (!nodeHeap.isEmpty()) { + NodeRecord record = nodeHeap.pop(); + Node cur = record.node; + int distance = record.distance; + for (Edge edge : cur.edges) { + nodeHeap.addOrUpdateOrIgnore(edge.to, edge.weight + distance); + } + result.put(cur, distance); } + return result; + } } diff --git a/src/main/java/nowcoder/NowCoder_AllLessNumSubArray.java b/src/main/java/nowcoder/NowCoder_AllLessNumSubArray.java new file mode 100644 index 0000000000000000000000000000000000000000..551c7570553b870b6832bb29f53f2beec03fd126 --- /dev/null +++ b/src/main/java/nowcoder/NowCoder_AllLessNumSubArray.java @@ -0,0 +1,65 @@ +// 链接:https://www.nowcoder.com/questionTerminal/5fe02eb175974e18b9a546812a17428e +// 来源:牛客网 +// +// 给定数组 arr 和整数 num,共返回有多少个子数组满足如下情况: +// max(arr[i...j]) - min(arr[i...j]) <= num +// max(arr[i...j])表示子数组arr[i...j]中的最大值,min[arr[i...j])表示子数组arr[i...j]中的最小值。 +package nowcoder; + +import java.util.LinkedList; +import java.util.Scanner; + +// 笔记:https://www.cnblogs.com/greyzeng/p/16966417.html +// arr[L..R]达标,则arr中内部的任何一个子数组都达标 +// arr[L..R]不达标,则arr扩充后肯定也不达标 +// L...R 范围如果达标,其子数组个数为:R - L +public class NowCoder_AllLessNumSubArray { + // 必须以l位置作为左边界的情况下,有多少达标的数组 + public static int getNum(int[] arr, int num) { + LinkedList qMax = new LinkedList<>(); + LinkedList qMin = new LinkedList<>(); + int ans = 0; + int l = 0; + int r = 0; + while (l < arr.length) { + while (r < arr.length) { + while (!qMax.isEmpty() && arr[qMax.peekLast()] <= arr[r]) { + qMax.pollLast(); + } + qMax.addLast(r); + while (!qMin.isEmpty() && arr[qMin.peekLast()] >= arr[r]) { + qMin.pollLast(); + } + qMin.addLast(r); + if (arr[qMax.peekFirst()] - arr[qMin.peekFirst()] > num) { + break; + } + r++; + } + // r是以l作为左边界,第一个不满足条件的位置 + ans += (r - l); + // 弹出过期位置 + if (!qMax.isEmpty() && qMax.peekFirst() == l) { + qMax.pollFirst(); + } + // 弹出过期位置 + if (!qMin.isEmpty() && qMin.peekFirst() == l) { + qMin.pollFirst(); + } + l++; + } + return ans; + } + + public static void main(String[] args) { + Scanner in = new Scanner(System.in); + int n = in.nextInt(); + int m = in.nextInt(); + int[] arr = new int[n]; + for (int i = 0; i < n; i++) { + arr[i] = in.nextInt(); + } + System.out.println(getNum(arr,m)); + in.close(); + } +} diff --git a/src/main/java/snippet/Code_0087_AllLessNumSubArray.java b/src/main/java/snippet/Code_0087_AllLessNumSubArray.java deleted file mode 100644 index 35fdd51ade91dec8afa8fa3784c5081c42b1eea2..0000000000000000000000000000000000000000 --- a/src/main/java/snippet/Code_0087_AllLessNumSubArray.java +++ /dev/null @@ -1,151 +0,0 @@ -//链接:https://www.nowcoder.com/questionTerminal/5fe02eb175974e18b9a546812a17428e -// 来源:牛客网 -// -// 给定数组 arr 和整数 num,共返回有多少个子数组满足如下情况: -// max(arr[i...j]) - min(arr[i...j]) <= num -// max(arr[i...j])表示子数组arr[i...j]中的最大值,min[arr[i...j])表示子数组arr[i...j]中的最小值。 -// -// -// 输入描述: -// -// 第一行输入两个数 n 和 num,其中 n 表示数组 arr 的长度 -// 第二行输入n个整数XiX_iXi​,表示数组arr中的每个元素 -// -// -// -// 输出描述: -// -// 输出给定数组中满足条件的子数组个数 -// -// 示例1 -// 输入 -// -// 5 2 -// 1 2 3 4 5 -// -// 输出 -// -// 12 -// -// -// 备注: -// -// 1≤n≤1000000 -// −1000000≤arri≤1000000 -// 0≤num≤20000000 -package snippet; - -import java.util.LinkedList; - -// arr[L..R]达标,则arr中内部的任何一个子数组都达标 -// arr[L..R]不达标,则arr扩充后肯定也不达标 -// L...R 范围如果达标,其子数组个数为:R - L -public class Code_0087_AllLessNumSubArray { - // 必须以l位置作为左边界的情况下,有多少达标的数组 - public static int getNum(int[] arr, int num) { - LinkedList qMax = new LinkedList<>(); - LinkedList qMin = new LinkedList<>(); - int ans = 0; - int l = 0; - int r = 0; - while (l < arr.length) { - while (r < arr.length) { - while (!qMax.isEmpty() && arr[qMax.peekLast()] <= arr[r]) { - qMax.pollLast(); - } - qMax.addLast(r); - while (!qMin.isEmpty() && arr[qMin.peekLast()] >= arr[r]) { - qMin.pollLast(); - - } - qMin.addLast(r); - if (arr[qMax.peekFirst()] - arr[qMin.peekFirst()] > num) { - break; - } - r++; - } - // r是以l作为左边界,第一个不满足条件的位置 - ans += (r - l); - // 弹出过期位置 - if (!qMax.isEmpty() && qMax.peekFirst() == l) { - qMax.pollFirst(); - } - // 弹出过期位置 - if (!qMin.isEmpty() && qMin.peekFirst() == l) { - qMin.pollFirst(); - } - l++; - } - return ans; - } - - - // 暴力的对数器方法 - public static int right(int[] arr, int sum) { - if (arr == null || arr.length == 0 || sum < 0) { - return 0; - } - int N = arr.length; - int count = 0; - for (int L = 0; L < N; L++) { - for (int R = L; R < N; R++) { - int max = arr[L]; - int min = arr[L]; - for (int i = L + 1; i <= R; i++) { - max = Math.max(max, arr[i]); - min = Math.min(min, arr[i]); - } - if (max - min <= sum) { - count++; - } - } - } - return count; - } - - - // for test - public static int[] generateRandomArray(int maxLen, int maxValue) { - int len = (int) (Math.random() * (maxLen + 1)); - int[] arr = new int[len]; - for (int i = 0; i < len; i++) { - arr[i] = (int) (Math.random() * (maxValue + 1)) - (int) (Math.random() * (maxValue + 1)); - } - return arr; - } - - // for test - public static void printArray(int[] arr) { - if (arr != null) { - for (int i = 0; i < arr.length; i++) { - System.out.print(arr[i] + " "); - } - System.out.println(); - } - } - - public static void main(String[] args) { - int maxLen = 100; - int maxValue = 200; - int testTime = 100000; - System.out.println("测试开始"); - for (int i = 0; i < testTime; i++) { - int[] arr = generateRandomArray(maxLen, maxValue); - int sum = (int) (Math.random() * (maxValue + 1)); - int ans1 = right(arr, sum); - int ans2 = getNum(arr, sum); - if (ans1 != ans2) { - System.out.println("Oops!"); - printArray(arr); - System.out.println(sum); - System.out.println(ans1); - System.out.println(ans2); - break; - } - } - System.out.println("测试结束"); - - } - - -}