A - Spoiler
题目:
给一个包含了两个 |
和小写字母的字符串,输出两个 |
之间的子字符串(不包括|
)
思路
使用 indexOf
和 lastIndexOf
找出前后 |
的下标,利用 substring
输出子串即可
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
class Main {
private static InputStream is = System.in;
private static final BufferedReader in = new BufferedReader(new InputStreamReader(is));
private static final PrintWriter out = new PrintWriter(System.out);
static void solve() throws IOException {
String s = in.readLine();
int a = s.indexOf('|'), b = s.lastIndexOf('|');
out.println(s.substring(0, a) + s.substring(b + 1));
}
public static void main(String[] args) throws IOException {
int t = 1;
t = Integer.parseInt(in.readLine());
while (t -- > 0) {
solve();
}
in.close();
out.flush();
out.close();
}
}
B - Delimiter
题目:
给N个整数,一行一个整数,但是不给出N值,确保第N个数一定为0,倒序输出序列
思路:
判断读入的数是否为0,为0就停止读入即可
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
class Main {
private static InputStream is = System.in;
private static final BufferedReader in = new BufferedReader(new InputStreamReader(is));
private static final PrintWriter out = new PrintWriter(System.out);
static void solve() throws IOException {
int t = -1;
List<Integer> list = new ArrayList<>();
while (t != 0) {
t = Integer.parseInt(in.readLine());
list.add(t);
}
for (int i = list.size() - 1; i >= 0; i --) {
out.println(list.get(i));
}
}
public static void main(String[] args) throws IOException {
int t = 1;
// t = Integer.parseInt(in.readLine());
while (t -- > 0) {
solve();
}
in.close();
out.flush();
out.close();
}
}
C - A+B+C
题目:
给出三个序列A、B、C,以及一个查询序列X,对于每个查询,判断是否能够从A、B、C各找出一个数,其总和等于查询值
思路:
题目数据ABC三个序列的长度最大只有100,因此可以先预处理出来从ABC各找一个数的总和,使用哈希表存储,查询时从哈希表中查询
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashSet;
import java.util.Set;
class Main {
private static InputStream is = System.in;
private static final BufferedReader in = new BufferedReader(new InputStreamReader(is));
private static final PrintWriter out = new PrintWriter(System.out);
static void solve() throws IOException {
int n = Integer.parseInt(in.readLine());
String[] ins = in.readLine().split(" ");
int[] a = new int[n];
for (int i = 0; i < n; i++) {
a[i] = Integer.parseInt(ins[i]);
}
int m = Integer.parseInt(in.readLine());
ins = in.readLine().split(" ");
int[] b = new int[m];
for (int i = 0; i < m; i++) {
b[i] = Integer.parseInt(ins[i]);
}
int l = Integer.parseInt(in.readLine());
int[] c = new int[l];
ins = in.readLine().split(" ");
for (int i = 0; i < l; i++) {
c[i] = Integer.parseInt(ins[i]);
}
Set<Long> st = new HashSet<>();
for (int i : a) {
for (int j : b) {
for (int k : c) {
st.add((long) (i + j + k));
}
}
}
int q = Integer.parseInt(in.readLine());
ins = in.readLine().split(" ");
for (int i = 0; i < q; i++) {
Long t = Long.parseLong(ins[i]);
if (st.contains(t)) {
out.println("Yes");
} else {
out.println("No");
}
}
}
public static void main(String[] args) throws IOException {
int t = 1;
// t = Integer.parseInt(in.readLine());
while (t -- > 0) {
solve();
}
in.close();
out.flush();
out.close();
}
}
D - String Bags
题意:
给出一个字符串 t
,以及N个背包,每个背包都有若干个字符串;
初始空串s
,执行N次操作,第i次操作在第i个背包中最多选择一个字符串并拼接到s
后面,求使 s
等于 t
的最小操作数,如果不能则输出 -1
思路:
一开始使用爆搜,但是TLE
// TLE 代码
static int ans = Integer.MAX_VALUE;
static void solve() throws IOException {
String t = in.readLine();
int n = Integer.parseInt(in.readLine());
List<String[]> bags = new ArrayList<>();
for (int i = 0; i < n; i ++) {
String[] ins = in.readLine().split(" ");
bags.add(ins);
}
dfs(bags, 0, 0, "", t);
out.print(ans == Integer.MAX_VALUE ? -1 : ans);
}
static void dfs(List<String[]> bags, int idx, int cnt, String cur, String target) {
if (idx == bags.size() || cur.length() >= target.length()) {
if (cur.equals(target)) {
ans = Math.min(ans, cnt);
}
return;
}
if (target.indexOf(cur) != 0) return;
String[] bag = bags.get(idx);
for (int i = 1; i < bag.length; i ++) {
dfs(bags, idx + 1, cnt + 1, cur + bag[i], target);
}
dfs(bags, idx + 1, cnt, cur, target);
}
背包的选择是按顺序的,那么第 i 个背包的选择是基于前面 1~i -1 背包的选择,这种是一个动态规划
如果第 i 个背包中选择的字符串s能够与t[j : j + len(s)]
部分匹配,那么该子问题转移为第 i - 1个背包中能够与 t[ : j]
匹配的最小操作数
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
class Main {
private static InputStream is = System.in;
private static final BufferedReader in = new BufferedReader(new InputStreamReader(is));
private static final PrintWriter out = new PrintWriter(System.out);
static void solve() throws IOException {
String t = in.readLine();
int n = Integer.parseInt(in.readLine());
List<String[]> bags = new ArrayList<>();
for (int i = 0; i < n; i ++) {
String[] ins = in.readLine().split(" ");
bags.add(ins);
}
int len = t.length();
int[][] dp = new int[n + 1][len + 1]; // 选择第 i 个背包时,与t的前j个字符相同的最小操作数
for (int i = 0; i <= n; i ++) {
Arrays.fill(dp[i], Integer.MAX_VALUE >> 1);
}
dp[0][0] = 0;
for (int i = 0; i < n; i ++) {
String[] bag = bags.get(i);
for (int j = 0; j <= len; j ++) {
// 如果不选择当前背包的任何字符串
dp[i + 1][j] = Math.min(dp[i][j], dp[i + 1][j]);
for (int k = 1; k < bag.length; k ++) {
int strLen = bag[k].length();
// 判断当前字符串能否放在[j, j + strLen)处
if (j + strLen <= len && t.substring(j, j + strLen).equals(bag[k])) {
dp[i + 1][j + strLen] = Math.min(dp[i + 1][j + strLen], dp[i][j] + 1);
}
}
}
}
out.println(dp[n][len] == Integer.MAX_VALUE >> 1 ? -1 : dp[n][len]);
}
public static void main(String[] args) throws IOException {
int t = 1;
// t = Integer.parseInt(in.readLine());
while (t -- > 0) {
solve();
}
in.close();
out.flush();
out.close();
}
}
E - Insert or Erase
题意:
给一个序列A,每个元素都不相同,执行Q次操作,每次操作都执行下面操作之一:
1 x y
立即插入y到x后面2 x
立即移除x
输出执行Q次操作后的序列
思路:
双向链表实现:
1 x y
仅需要修改 x 和 x 的后面元素2 x
仅需要 x 的前面元素和后面元素
使用哈希表存储每个元素对应的前面元素和后面元素,记得需要添加哨兵元素,方便查找表头和判断表尾
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
class Main {
private static InputStream is = System.in;
private static final BufferedReader in = new BufferedReader(new InputStreamReader(is));
private static final PrintWriter out = new PrintWriter(System.out);
static void solve() throws IOException {
int n = Integer.parseInt(in.readLine());
int[] a = new int[n];
Map<Integer, Integer> pre = new HashMap<>(), next = new HashMap<>();
String[] ins = in.readLine().split(" ");
for (int i = 0; i < n; i ++) {
a[i] = Integer.parseInt(ins[i]);
}
// 初始化双向链表
for (int i = 0; i < n; i ++) {
pre.put(a[i], i == 0 ? -1 : a[i - 1]);
next.put(a[i], i == n - 1 ? -1 : a[i + 1]);
}
// 设置表头哨兵,表尾哨兵在上面
next.put(0, a[0]);
pre.put(a[0], 0);
int q = Integer.parseInt(in.readLine());
while (q -- > 0) {
ins = in.readLine().split(" ");
int op = Integer.parseInt(ins[0]);
if (op == 1) {
int x = Integer.parseInt(ins[1]), y = Integer.parseInt(ins[2]);
int nxt = next.get(x);
pre.put(y, x); // 新插入的y前面为x
next.put(y, nxt); // 新插入的y后面为nxt
pre.put(nxt, y);
next.put(x, y);
} else {
int x = Integer.parseInt(ins[1]);
int prev = pre.get(x), nxt = next.get(x);
pre.put(nxt, prev); // 将 x 的前面元素和后面元素相互联系即可
next.put(prev, nxt);
}
}
int t = next.get(0); // 表头哨兵节点
while (t != -1) { // 判断表尾
out.print(t + " ");
t = next.get(t);
}
}
public static void main(String[] args) throws IOException {
int t = 1;
// t = Integer.parseInt(in.readLine());
while (t -- > 0) {
solve();
}
in.close();
out.flush();
out.close();
}
}