参考
【数据结构1-1】线性表 - 题单 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
- P3156 【深基15.例1】询问学号
- P3613 【深基15.例2】寄包柜
- P1449 后缀表达式
- P1996 约瑟夫问题
- P1160 队列安排
- P1540 [NOIP2010 提高组] 机器翻译
- P2058 [NOIP2016 普及组] 海港
- P1241 括号序列
- P4387 【深基15.习9】验证栈序列
- P2234 [HNOI2002] 营业额统计
动态数组
P3613 【深基15.例2】寄包柜
使用了嵌套map来表示嵌套的kv对应,如果用list的话不能对应离散的kv,必须连续的(例如初始的时候加入第10个柜子第10号格子的物品,那List就要创建10大小,每次都要这样操作十分不便)。map就可以用来解决离散k+动态数组,十分的不错。
本来20%,仔细看了下题目有个k=0表示清空操作,补充了一下就AC了
package _1_1;
import java.io.*;
import java.util.HashMap;
public class P3613 {
public static void main(String[] args) throws IOException {
StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
PrintWriter out = new PrintWriter(System.out);
in.nextToken();
int n = (int) in.nval;
in.nextToken();
int q = (int) in.nval;
int op, i, j, k;
// 用map来存储,key表示第几个柜子,value用一个map表示格子,key表示格子编号,value表示格子内容
HashMap<Integer, HashMap<Integer, Integer>> map = new HashMap<>();
while (q-- > 0) {
in.nextToken();
op = (int) in.nval;
if (op == 1) {
// 存,注意k==0表示清空格子
in.nextToken();
i = (int) in.nval;
in.nextToken();
j = (int) in.nval;
in.nextToken();
k = (int) in.nval;
// 先判断柜子存不存在
if (!map.containsKey(i)) {
// 创建柜子直接放入
HashMap<Integer, Integer> gezi = new HashMap<>();
gezi.put(j, k);
map.put(i, gezi);
} else {
// 柜子i存在,判断格子j存不存在
HashMap<Integer, Integer> gezi = map.get(i);
if (!gezi.containsKey(j)) {
// 在原有格子map中放入新得key(这里容易混)
gezi.put(j, k);
map.put(i, gezi);
} else {
// 重复放入物品(这里会涉及到清空)
// 上面的操作都是直接放入k,就算k=0也不影响,但是重复是需要加法得
if (k != 0) {
Integer integer = gezi.get(j);
gezi.put(j, integer + k);
} else {
gezi.put(j, k);
}
map.put(i, gezi);
}
}
} else {
// 查
in.nextToken();
i = (int) in.nval;
in.nextToken();
j = (int) in.nval;
// 保证查询的柜子有存过东西,这里不用判断
out.println(map.get(i).get(j));
}
}
out.flush();
out.close();
}
}
栈
使用LinkedList实现,注意add和poll同一个First或者Last
P1449 后缀表达式
知道后缀表达式怎么求结果即可,注意取出来后操作符的计算顺序
package _1_1.stack;
import java.util.LinkedList;
import java.util.Scanner;
public class P1449 {
// algo 后缀表达式求结果值
// 遇到操作数压入栈,遇到操作符,把栈中前两个数取出来计算,再把结果压入栈
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String line = scanner.nextLine();
LinkedList<Integer> list = new LinkedList<>();
int opNum = 0;
for (char c : line.toCharArray()) {
if (Character.isDigit(c)) {
// !注意此处char-int
opNum = opNum * 10 + c - '0';
} else if (c == '.') {
// 操作数读取结束,压入栈
list.addLast(opNum);
opNum = 0;
} else if (c == '@') {
// 结束符
System.out.println(list.pollLast());
break;
} else {
Integer num1 = list.pollLast();
Integer num2 = list.pollLast();
if (c == '+')
list.addLast(num1 + num2);
else if (c == '-')
// 注意是 左操作数(后出的) - 右操作数(先出的)
list.addLast(num2 - num1);
else if (c == '*')
list.addLast(num1 * num2);
else
// 注意是 左操作数(后出的) / 右操作数(先出的)
list.addLast(num2 / num1);
}
}
scanner.close();
}
}
P1241 括号序列
一般WA,应该是题目没理解对,算了懒得。
package _1_1.stack;
import java.util.LinkedList;
import java.util.Scanner;
public class P1241 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
StringBuilder line = new StringBuilder(scanner.nextLine());
for (int i = 0; i < line.length(); i++) {
if (line.charAt(i) == ']') {
// 往左找
for (int j = i - 1; j >= 0; j--) {
if (line.charAt(j) == '[') {
// 这里用一个别的符号代替匹配的两个括号,防止length的问题
line.replace(j, j + 1, " ");
line.replace(i, i + 1, " ");
System.out.print("[]");
break;
} else if (line.charAt(j) == '(') {
break;
}
// 找到一个左括号就退出
}
} else if (line.charAt(i) == ')') {
for (int j = i - 1; j >= 0; j--) {
if (line.charAt(j) == '(') {
// 这里用一个别的符号代替匹配的两个括号,防止length的问题
line.replace(j, j + 1, " ");
line.replace(i, i + 1, " ");
System.out.print("()");
break;
} else if (line.charAt(j) == '[') {
break;
}
}
}
}
// 把没匹配的手动匹配输出(这里要逆序)
for (int i = line.length() - 1; i >= 0; i--) {
char c = line.charAt(i);
if (c != ' ') {
if (c == '(' || c == ')') {
System.out.print("()");
} else if (c == '[' || c == ']') {
System.out.print("[]");
}
}
}
scanner.close();
}
public static void fun() {
Scanner scanner = new Scanner(System.in);
// 没有匹配的要手动匹配输出,成功匹配的记得把栈里的取出来再输出,最后栈里剩下的也手动匹配输出
String line = scanner.nextLine();
// 一个栈只放未匹配左括号,一个放所有未匹配
LinkedList<Character> left = new LinkedList<>();
LinkedList<Character> all = new LinkedList<>();
for (char c : line.toCharArray()) {
if (c == '(' || c == '[') {
left.addLast(c);
all.addLast(c);
} else {
// 注意题目:中间可能配对失败,但是最后才是把所有没配对的手动配对,如([)[ - []()[]() 而不是()[][]()
// 注意匹配成功后all中也要去除左括号,但是由于混放不知道左括号的位置,所以这道题感觉不如直接模拟
if (c == ')') {
if (left.getLast() == '(') {
// 成功匹配
left.pollLast();
System.out.print("()");
} else {
// 没配对放入所有未匹配栈,左括号栈里面的不弹出
all.addLast(c);
}
} else {
if (left.getLast() == '[') {
// 成功匹配
left.pollLast();
System.out.print("[]");
} else {
// 没配对放入所有未匹配栈,左括号栈里面的不弹出
all.addLast(c);
}
}
}
}
while (!all.isEmpty()) {
Character c = all.pollLast();
if (c == '(' || c == ')') {
System.out.print("()");
} else if (c == '[' || c == ']') {
System.out.print("[]");
}
}
scanner.close();
}
}
队列
使用LinkedList实现,注意add和poll不同First和Last
BFS使用队列实现。
P1540 [NOIP2010 提高组] 机器翻译
package _1_1.queue;
import java.util.LinkedList;
import java.util.Scanner;
public class P1540 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int m = scanner.nextInt();
LinkedList<Integer> list = new LinkedList<>();
int count = 0;
for (int i = 1; i <= m; i++) {
int k = scanner.nextInt();
if (!list.contains(k)) {
count++;
// 查外村并且加入内存,如果内存满了就先去除最早的元素
if (list.size() == n) {
list.removeFirst();
}
list.addLast(k);
}
}
System.out.println(count);
scanner.close();
}
}
链表
使用LinkedList实现
P1996 约瑟夫问题
循环下标+标记数组
package _1_1.queue;
import java.util.Scanner;
public class P1996 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int m = scanner.nextInt();
// 记录是否已经出局
boolean[] out = new boolean[n + 1];
// algo 循环数组
// index:1~n,所以index%(n+1)+1
// 从第一个人之前开始
int now = 0;
// 出来n个人
for (int i = 1; i <= n; i++) {
// k表示当前报数
int k = 1;
while (k <= m) {
now++;
if (now == n + 1) now = 1;
if (!out[now]) k++;
}
out[now] = true;
System.out.printf("%d ", now);
}
scanner.close();
}
}
链表
P2234 [HNOI2002] 营业额统计
解法1:平衡树
解法2:看题干,就是要找和当前数最接近的那个数,Java中有个TreeMap,自带排序,就不用自己写list+sort+二分了,灵感来自题解中c++的lower_bound,Java中没有直接对应的,但是百度一下找到了TreeMap。
TreeMap用的红黑树实现(没学过,不会)。
TreeSet中有四个方法,分别可以获得当前指定值在有序序列中的最接近数。
详细可以见TreeMap的实现方法
- Ceiling表示
返回>=k的最小值
,不存在则返回null - Flooring表示
返回<=k的最大值
- Higher表示
返回>k的最小值
,不存在则返回null - Lower表示
返回<k的最大值
还是很好用的,直接AC
package _1_1.Ttree;
import java.util.Scanner;
import java.util.TreeSet;
public class P2234 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
TreeSet<Integer> treeSet = new TreeSet<>();
int result = 0;
Integer ceiling = 0, floor = 0, min = 0;
while (n-- > 0) {
int k = scanner.nextInt();
// 注意先找min,再加入当前营业额
if (treeSet.size() == 0) {
// 第一天不用找
result += k;
} else {
// algo TreeMap:最接近数
// 找到最接近当前营业额的数,加入结果
ceiling = treeSet.ceiling(k);
floor = treeSet.floor(k);
if (ceiling != null && floor != null) {
min = Math.min(Math.abs(ceiling - k), Math.abs(floor - k));
} else if (ceiling != null) {
min = Math.abs(ceiling - k);
} else if (floor != null) {
min = Math.abs(floor - k);
}
result += min;
}
// 把当前营业额加入序列
treeSet.add(k);
}
System.out.println(result);
scanner.close();
}
}
;
} else if (ceiling != null) {
min = Math.abs(ceiling - k);
} else if (floor != null) {
min = Math.abs(floor - k);
}
result += min;
}
// 把当前营业额加入序列
treeSet.add(k);
}
System.out.println(result);
scanner.close();
}
}