modify code

master
algorithmzuo 3 years ago
parent e856d967cb
commit 3ef438893d

@ -0,0 +1,106 @@
package class_2022_08_3_week;
import java.util.ArrayList;
// 给你一个 n 个节点的 有向图 节点编号为 0  n - 1 其中每个节点 至多 有一条出边。
// 图用一个大小为 n 下标从 0 开始的数组 edges 表示
// 节点 i 到节点 edges[i] 之间有一条有向边。如果节点 i 没有出边那么 edges[i] == -1 
// 请你返回图中的 最长 环,如果没有任何环,请返回 -1 
// 一个环指的是起点和终点是 同一个 节点的路径。
// 用强联通分量
// 测试链接 : https://leetcode.cn/problems/longest-cycle-in-a-graph/
public class Code01_LongestCycleInGraph1 {
public static int longestCycle(int[] edges) {
int n = edges.length;
ArrayList<ArrayList<Integer>> graph = new ArrayList<ArrayList<Integer>>();
for (int i = 0; i < n; i++) {
graph.add(new ArrayList<Integer>());
}
for (int i = 0; i < n; i++) {
if (edges[i] != -1) {
graph.get(i).add(edges[i]);
}
}
StronglyConnectedComponents connectedComponents = new StronglyConnectedComponents(graph);
int m = connectedComponents.getSccn() + 1;
int[] cnt = new int[m];
int[] scc = connectedComponents.getScc();
for (int i = 0; i < n; i++) {
cnt[scc[i]]++;
}
int ans = -1;
for (int count : cnt) {
ans = Math.max(ans, count > 1 ? count : -1);
}
return ans;
}
public static class StronglyConnectedComponents {
public ArrayList<ArrayList<Integer>> nexts;
public int n;
public int stackSize;
public int cnt;
public int sccn;
public int[] stack;
public int[] dfn;
public int[] low;
public int[] scc;
public StronglyConnectedComponents(ArrayList<ArrayList<Integer>> edges) {
nexts = edges;
init();
scc();
}
private void init() {
n = nexts.size();
stackSize = 0;
cnt = 0;
sccn = 0;
stack = new int[n];
dfn = new int[n];
low = new int[n];
scc = new int[n];
}
private void scc() {
for (int i = 0; i < n; i++) {
if (dfn[i] == 0) {
tarjan(i);
}
}
}
private void tarjan(int p) {
low[p] = dfn[p] = ++cnt;
stack[stackSize++] = p;
for (int q : nexts.get(p)) {
if (dfn[q] == 0) {
tarjan(q);
}
if (scc[q] == 0) {
low[p] = Math.min(low[p], low[q]);
}
}
if (low[p] == dfn[p]) {
sccn++;
int top = 0;
do {
top = stack[--stackSize];
scc[top] = sccn;
} while (top != p);
}
}
public int[] getScc() {
return scc;
}
public int getSccn() {
return sccn;
}
}
}

@ -0,0 +1,40 @@
package class_2022_08_3_week;
// 给你一个 n 个节点的 有向图 节点编号为 0  n - 1 
// 其中每个节点 至多 有一条出边。
// 图用一个大小为 n 下标从 0 开始的数组 edges 表示
// 节点 i 到节点 edges[i] 之间有一条有向边。
// 如果节点 i 没有出边那么 edges[i] == -1 
// 请你返回图中的 最长 环,如果没有任何环,请返回 -1 
// 一个环指的是起点和终点是 同一个 节点的路径。
// 测试链接 : https://leetcode.cn/problems/longest-cycle-in-a-graph/
public class Code01_LongestCycleInGraph2 {
public int longestCycle(int[] edges) {
// edges[i] = j i -> j
// edges[i] = -1 i X
int n = edges.length;
int[] ids = new int[n];
// 发现的最大环,有几个点!
int ans = -1;
for (int from = 0, cnt = 1; from < n; from++) {
if (ids[from] == 0) {
for (int cur = from, fromId = cnt; cur != -1;
cur = edges[cur]) {
// from -> -> cur ->
if (ids[cur] > 0) {
// 访问过,此时的环,之前遍历过的点
if (ids[cur] >= fromId) { // 新的环
ans = Math.max(ans, cnt - ids[cur]);
}
// 如果上面的if不成立老的点直接跳出
break;
}
ids[cur] = cnt++;
}
}
}
return ans;
}
}

@ -0,0 +1,119 @@
package class_2022_08_3_week;
// 来自学员问题
// 给定怪兽的血量为hp
// 第i回合如果用刀砍怪兽在这回合会直接掉血没有后续效果
// 第i回合如果用毒怪兽在这回合不会掉血
// 但是之后每回合都会掉血,并且所有中毒的后续效果会叠加
// 给定的两个数组cuts、poisons两个数组等长长度都是n
// 表示你在n回合内的行动
// 每一回合的刀砍的效果由cuts[i]表示
// 每一回合的中毒的效果由poisons[i]表示
// 如果你在n个回合内没有直接杀死怪兽意味着你已经无法有新的行动了
// 但是怪兽如果有中毒效果的话那么怪兽依然会在hp耗尽的那回合死掉
// 返回你最快能在多少回合内将怪兽杀死
// 数据范围 :
// 1 <= n <= 10的5次方
// 1 <= hp <= 10的9次方
// 1 <= cuts[i]、poisons[i] <= 10的9次方
public class Code02_CutOrPoison {
// 不算好的方法
// 为了验证
public static int fast1(int[] cuts, int[] poisons, int hp) {
int sum = 0;
for (int num : poisons) {
sum += num;
}
int[][][] dp = new int[cuts.length][hp + 1][sum + 1];
return process1(cuts, poisons, 0, hp, 0, dp);
}
public static int process1(int[] cuts, int[] poisons, int index, int restHp, int poisonEffect, int[][][] dp) {
restHp -= poisonEffect;
if (restHp <= 0) {
return index + 1;
}
// restHp > 0
if (index == cuts.length) {
if (poisonEffect == 0) {
return Integer.MAX_VALUE;
} else {
return cuts.length + 1 + (restHp + poisonEffect - 1) / poisonEffect;
}
}
if (dp[index][restHp][poisonEffect] != 0) {
return dp[index][restHp][poisonEffect];
}
int p1 = restHp <= cuts[index] ? (index + 1)
: process1(cuts, poisons, index + 1, restHp - cuts[index], poisonEffect, dp);
int p2 = process1(cuts, poisons, index + 1, restHp, poisonEffect + poisons[index], dp);
int ans = Math.min(p1, p2);
dp[index][restHp][poisonEffect] = ans;
return ans;
}
// 真正想实现的方法
// O(N * log(hp))
public static int fast2(int[] cuts, int[] poisons, int hp) {
// 怪兽可能的最快死亡回合
int l = 1;
// 怪兽可能的最晚死亡回合
int r = hp + 1;
int m = 0;
int ans = Integer.MAX_VALUE;
while (l <= r) {
m = l + ((r - l) >> 1);
if (ok(cuts, poisons, hp, m)) {
ans = m;
r = m - 1;
} else {
l = m + 1;
}
}
return ans;
}
public static boolean ok(int[] cuts, int[] posions, long hp, int limit) {
int n = Math.min(cuts.length, limit);
for (int i = 0, j = 1; i < n; i++, j++) {
hp -= Math.max((long) cuts[i], (long) (limit - j) * (long) posions[i]);
if (hp <= 0) {
return true;
}
}
return false;
}
// 为了测试
public static int[] randomArray(int n, int v) {
int[] ans = new int[n];
for (int i = 0; i < n; i++) {
ans[i] = (int) (Math.random() * v) + 1;
}
return ans;
}
// 为了测试
public static void main(String[] args) {
int N = 30;
int cutV = 20;
int posionV = 10;
int hpV = 200;
int testTimes = 10000;
System.out.println("测试开始");
for (int i = 0; i < testTimes; i++) {
int n = (int) (Math.random() * N) + 1;
int[] cuts = randomArray(n, cutV);
int[] posions = randomArray(n, posionV);
int hp = (int) (Math.random() * hpV) + 1;
int ans1 = fast1(cuts, posions, hp);
int ans2 = fast2(cuts, posions, hp);
if (ans1 != ans2) {
System.out.println("出错了!");
}
}
System.out.println("测试结束");
}
}

@ -0,0 +1,191 @@
package class_2022_08_3_week;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
// 设计一个最大栈数据结构,既支持栈操作,又支持查找栈中最大元素。
// 实现 MaxStack 
// MaxStack() 初始化栈对象
// void push(int x) 将元素 x 压入栈中。
// int pop() 移除栈顶元素并返回这个元素。
// int top() 返回栈顶元素,无需移除。
// int peekMax() 检索并返回栈中最大元素,无需移除。
// int popMax() 检索并返回栈中最大元素,并将其移除。
// 如果有多个最大元素,只要移除 最靠近栈顶 的那个。
// 测试链接 : https://leetcode.cn/problems/max-stack/
public class Code03_MaxStack {
class MaxStack {
public int cnt;
public HeapGreater<Node> heap;
public Node top;
public MaxStack() {
cnt = 0;
heap = new HeapGreater<>(new NodeComparator());
top = null;
}
public void push(int x) {
Node cur = new Node(x, ++cnt);
heap.push(cur);
if (top == null) {
top = cur;
} else {
top.last = cur;
cur.next = top;
top = cur;
}
}
public int pop() {
Node ans = top;
if (top.next == null) {
top = null;
} else {
top = top.next;
top.last = null;
}
heap.remove(ans);
return ans.val;
}
public int top() {
return top.val;
}
public int peekMax() {
return heap.peek().val;
}
public int popMax() {
Node ans = heap.pop();
if (ans == top) {
if (top.next == null) {
top = null;
} else {
top = top.next;
top.last = null;
}
} else {
if (ans.next != null) {
ans.next.last = ans.last;
}
if (ans.last != null) {
ans.last.next = ans.next;
}
}
return ans.val;
}
class Node {
public int val;
public int cnt;
public Node next;
public Node last;
public Node(int v, int c) {
val = v;
cnt = c;
}
}
class NodeComparator implements Comparator<Node> {
@Override
public int compare(Node o1, Node o2) {
return o1.val != o2.val ? (o2.val - o1.val) : (o2.cnt - o1.cnt);
}
}
class HeapGreater<T> {
private ArrayList<T> heap;
private HashMap<T, Integer> indexMap;
private int heapSize;
private Comparator<? super T> comp;
public HeapGreater(Comparator<? super T> c) {
heap = new ArrayList<>();
indexMap = new HashMap<>();
heapSize = 0;
comp = c;
}
public T peek() {
return heap.get(0);
}
public void push(T obj) {
heap.add(obj);
indexMap.put(obj, heapSize);
heapInsert(heapSize++);
}
public T pop() {
T ans = heap.get(0);
swap(0, heapSize - 1);
indexMap.remove(ans);
heap.remove(--heapSize);
heapify(0);
return ans;
}
public void remove(T obj) {
T replace = heap.get(heapSize - 1);
int index = indexMap.get(obj);
indexMap.remove(obj);
heap.remove(--heapSize);
if (obj != replace) {
heap.set(index, replace);
indexMap.put(replace, index);
resign(replace);
}
}
private void resign(T obj) {
heapInsert(indexMap.get(obj));
heapify(indexMap.get(obj));
}
private void heapInsert(int index) {
while (comp.compare(heap.get(index), heap.get((index - 1) / 2)) < 0) {
swap(index, (index - 1) / 2);
index = (index - 1) / 2;
}
}
private void heapify(int index) {
int left = index * 2 + 1;
while (left < heapSize) {
int best = left + 1 < heapSize && comp.compare(heap.get(left + 1), heap.get(left)) < 0 ? (left + 1)
: left;
best = comp.compare(heap.get(best), heap.get(index)) < 0 ? best : index;
if (best == index) {
break;
}
swap(best, index);
index = best;
left = index * 2 + 1;
}
}
private void swap(int i, int j) {
T o1 = heap.get(i);
T o2 = heap.get(j);
heap.set(i, o2);
heap.set(j, o1);
indexMap.put(o2, i);
indexMap.put(o1, j);
}
}
}
}

@ -0,0 +1,33 @@
package class_2022_08_3_week;
// 这里有 n 个航班它们分别从 1 到 n 进行编号。
// 有一份航班预订表 bookings
// 表中第 i 条预订记录 bookings[i] = [firsti, lasti, seatsi]
// 意味着在从 firsti 到 lasti
//(包含 firsti 和 lasti )的 每个航班 上预订了 seatsi 个座位。
// 请你返回一个长度为 n 的数组 answer里面的元素是每个航班预定的座位总数。
// 测试链接 : https://leetcode.cn/problems/corporate-flight-bookings/
public class Code04_CorporateFlightBookings {
public static int[] corpFlightBookings(int[][] bookings, int n) {
// 1 2 3 4 n
// 0 1 2 3 .. n n+1
int[] cnt = new int[n + 2];
for (int[] book : bookings) {
// start book[0]
// end book[1]
// 票 book[2]
cnt[book[0]] += book[2];
cnt[book[1] + 1] -= book[2];
}
for (int i = 1; i < cnt.length; i++) {
cnt[i] += cnt[i - 1];
}
int[] ans = new int[n];
for (int i = 0; i < n; i++) {
ans[i] = cnt[i + 1];
}
return ans;
}
}

@ -0,0 +1,57 @@
package class_2022_08_3_week;
// 给你一个数组 nums我们可以将它按一个非负整数 k 进行轮调,
// 例如数组为 nums = [2,4,1,3,0]
// 我们按 k = 2 进行轮调后它将变成 [1,3,0,2,4]。
// 这将记为 3 分,
// 因为 1 > 0 [不计分]、3 > 1 [不计分]、0 <= 2 [计 1 分]、
// 2 <= 3 [计 1 分]4 <= 4 [计 1 分]。
// 在所有可能的轮调中,返回我们所能得到的最高分数对应的轮调下标 k 。
// 如果有多个答案,返回满足条件的最小的下标 k 。
// 测试链接 :
// https://leetcode.cn/problems/smallest-rotation-with-highest-score/
public class Code05_SmallestRotationWithHighestScore {
public static int bestRotation(int[] nums) {
int n = nums.length;
// cnt : 差分数组
// cnt最后进行前缀和的加工
// 加工完了的cnt[0] : 整体向右移动0的距离, 一共能得多少分
// 加工完了的cnt[i] : 整体向右移动i的距离, 一共能得多少分
int[] cnt = new int[n + 1];
for (int i = 0; i < n; i++) {
// 遍历每个数!
// 看看每个数,对差分数组哪些范围,会产生影响!
if (nums[i] < n) {
if (i <= nums[i]) {
add(cnt, nums[i] - i, n - i - 1);
} else {
add(cnt, 0, n - i - 1);
add(cnt, n - i + nums[i], n - 1);
}
}
}
for (int i = 1; i <= n; i++) {
cnt[i] += cnt[i - 1];
}
// 最大得分是啥!已经求出来了
int max = cnt[0];
int ans = 0;
for (int i = n - 1; i >= 1; i--) {
// 整体移动的i 0 n-1 n-2 n-3 1
// k 0 1 2 3 n-1
if (cnt[i] > max) {
max = cnt[i];
ans = i;
}
}
return ans == 0 ? 0 : (n - ans);
}
public static void add(int[] cnt, int l, int r) {
cnt[l]++;
cnt[r + 1]--;
}
}

@ -1573,5 +1573,64 @@ edges一定表示的是一个无环无向图也就是树结构
第036节 2022年8月第3周流行算法题目解析
给你一个 n 个节点的 有向图 节点编号为 0  n - 1 
其中每个节点 至多 有一条出边。
图用一个大小为 n 下标从 0 开始的数组 edges 表示
节点 i 到节点 edges[i] 之间有一条有向边。
如果节点 i 没有出边那么 edges[i] == -1 
请你返回图中的 最长 环,如果没有任何环,请返回 -1 
一个环指的是起点和终点是 同一个 节点的路径。
测试链接 : https://leetcode.cn/problems/longest-cycle-in-a-graph/
来自学员问题
给定怪兽的血量为hp
第i回合如果用刀砍怪兽在这回合会直接掉血没有后续效果
第i回合如果用毒怪兽在这回合不会掉血
但是之后每回合都会掉血,并且所有中毒的后续效果会叠加
给定的两个数组cuts、poisons两个数组等长长度都是n
表示你在n回合内的行动
每一回合的刀砍的效果由cuts[i]表示
每一回合的中毒的效果由poisons[i]表示
如果你在n个回合内没有直接杀死怪兽意味着你已经无法有新的行动了
但是怪兽如果有中毒效果的话那么怪兽依然会在hp耗尽的那回合死掉
返回你最快能在多少回合内将怪兽杀死
数据范围 :
1 <= n <= 10的5次方
1 <= hp <= 10的9次方
1 <= cuts[i]、poisons[i] <= 10的9次方
设计一个最大栈数据结构,既支持栈操作,又支持查找栈中最大元素。
实现 MaxStack 
MaxStack() 初始化栈对象
void push(int x) 将元素 x 压入栈中。
int pop() 移除栈顶元素并返回这个元素。
int top() 返回栈顶元素,无需移除。
int peekMax() 检索并返回栈中最大元素,无需移除。
int popMax() 检索并返回栈中最大元素,并将其移除。
如果有多个最大元素,只要移除 最靠近栈顶 的那个。
测试链接 : https://leetcode.cn/problems/max-stack/
这里有 n 个航班它们分别从 1 到 n 进行编号。
有一份航班预订表 bookings
表中第 i 条预订记录 bookings[i] = [firsti, lasti, seatsi]
意味着在从 firsti 到 lasti
(包含 firsti 和 lasti )的 每个航班 上预订了 seatsi 个座位。
请你返回一个长度为 n 的数组 answer里面的元素是每个航班预定的座位总数。
测试链接 : https://leetcode.cn/problems/corporate-flight-bookings/
给你一个数组 nums我们可以将它按一个非负整数 k 进行轮调,
例如数组为 nums = [2,4,1,3,0]
我们按 k = 2 进行轮调后它将变成 [1,3,0,2,4]。
这将记为 3 分,
因为 1 > 0 [不计分]、3 > 1 [不计分]、0 <= 2 [计 1 分]、
2 <= 3 [计 1 分]4 <= 4 [计 1 分]。
在所有可能的轮调中,返回我们所能得到的最高分数对应的轮调下标 k 。
如果有多个答案,返回满足条件的最小的下标 k 。
测试链接 :
https://leetcode.cn/problems/smallest-rotation-with-highest-score/

Loading…
Cancel
Save