【算法练习】Acwing第41周周赛
又又卡在了最后一题…(第二题卡了太多时间了,第二题的感觉就是很熟悉,但是又不知道哪里熟悉,搞半天没做出来,最后想了个简单方法)
一、最小值(简单)
就是打卡的
import java.io.*;
import java.util.*;
public class Main {
static BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
static BufferedWriter out = new BufferedWriter(new OutputStreamWriter(System.out));
public static void main(String[] args) throws IOException {
// String[] str = in.readLine().trim().split(" ");
Scanner scan = new Scanner(System.in);
int n = scan.nextInt();
int m = scan.nextInt();
int a = scan.nextInt();
int b = scan.nextInt();
double min = 1.0 * a / b;
for (int i = 1; i < n; ++i) {
a = scan.nextInt();
b = scan.nextInt();
min = Math.min(min, 1.0 * a / b);
}
System.out.printf("%.6f", m * min);
}
}
二、出现次数(中等)


就是这道题…一看就有动态规划那味,但是该怎么避免重复计算呢?我的方法是:
我只用遍历一次字符串a,统计以当前字符开头,能否能够构成字符串b(必须要包含当前字符),如果可以,那就是这个下标能够贡献1个b子串数目,统计完a的下标后,就可以根据左右l r来进行查询值了。
给出l、r值,我们只要累加这个区间内的贡献值即可,然是要注意 l 是开始下标,r 是结束下标,我们的贡献值是以开始节点来算的,所以我们不能累加到cnt[r],而是cnt[r - bLen]!!
import java.io.*;
import java.util.*;
public class Main {
static BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
static BufferedWriter out = new BufferedWriter(new OutputStreamWriter(System.out));
public static void main(String[] args) throws IOException {
String[] strr = in.readLine().trim().split(" ");
int n = Integer.parseInt(strr[0]);
int m = Integer.parseInt(strr[1]);
int q = Integer.parseInt(strr[2]);
String a = in.readLine().trim();
String b = in.readLine().trim();
int[] cnt = new int[n];
for (int i = 0; i < n; i++) {
String str = a.substring(i, n);
if (str.indexOf(b) == 0) cnt[i] = 1;
}
while (q-- > 0) {
strr = in.readLine().trim().split(" ");
int l = Integer.parseInt(strr[0]);
int r = Integer.parseInt(strr[1]);
int ans = 0;
// r作为结束下标,那它的开始下标:r - m
for (int i = l - 1; i <= r - m; i++) {
ans += cnt[i];
}
out.write(ans + "\n");
}
out.flush();
}
}
三、满二叉树等长路径(困难)


这道题是这周周赛最漂亮的一题,很考验对二叉树性质的掌握,代码很简单,但就看能不能想到。在读入路径长度时,顺便记录从根节点到叶子节点的长度,之后从叶子节点开始遍历,每次遍历两个叶子节点,记录根节点到它们之间距离的差值的绝对值,并把根节点的值更新为它们中的最大值,然后重复上面的操作,直到到达根节点,这个过程可以画图手推,很容易就发现规律了。
import java.io.*;
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int n = scan.nextInt();
n = (int)Math.pow(2, n + 1) - 1;
int[] len = new int[n + 1];
// 把边信息存在点上!
for (int i = 2; i <= n; i++) {
// 顺便求根节点到每个节点的距离
len[i] = scan.nextInt() + len[i / 2];
}
int ans = 0;
// 到根节点就不遍历了
for (int i = n; i >= 2; i -= 2) {
// 记录相邻节点的差值的绝对值
ans += Math.abs(len[i] - len[i - 1]);
// 更新根节点为两者的最大值
len[i / 2] = Math.max(len[i], len[i - 1]);
}
System.out.println(ans);
}
}
本文分享了算法练习中的三个难题:最小值计算通过迭代优化,动态规划解决字符串出现次数问题,以及利用二叉树特性求解满二叉树等长路径。理解并实现这些概念有助于提升编程技能和数据结构知识。
2万+

被折叠的 条评论
为什么被折叠?



