面向对象(OOP,OOD) Java 题解(入门级、普及级) (from 黄老师)
以下完整内容,包含题目名称、题号、洛谷链接和对应的面向对象Java题解:
一、P1001 A+B Problem
洛谷链接: https://www.luogu.com.cn/problem/P1001
面向对象适配点: 可封装Calculator类,用方法实现加法逻辑,入门级OOP实践
import java.util.Scanner;
class Calculator {
private int a;
private int b;
public Calculator(int a, int b) {
this.a = a;
this.b = b;
}
public int add() {
return this.a + this.b;
}
}
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int a = scanner.nextInt();
int b = scanner.nextInt();
Calculator calculator = new Calculator(a, b);
System.out.println(calculator.add());
scanner.close();
}
}
二、P1047 校门外的树
洛谷链接: https://www.luogu.com.cn/problem/P1047
面向对象适配点: 封装TreeZone类,管理区间、实现砍树/统计逻辑,体现封装特性
import java.util.Scanner;
class TreeZone {
private boolean[] trees;
public TreeZone(int length) {
trees = new boolean[length + 1];
for (int i = 0; i <= length; i++) {
trees[i] = true; // true表示树还在
}
}
public void removeTrees(int start, int end) {
for (int i = start; i <= end; i++) {
trees[i] = false; // false表示树被移除了
}
}
public int countRemainingTrees() {
int count = 0;
for (boolean tree : trees) {
if (tree) {
count++;
}
}
return count;
}
}
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int L = scanner.nextInt();
int M = scanner.nextInt();
TreeZone treeZone = new TreeZone(L);
for (int i = 0; i < M; i++) {
int start = scanner.nextInt();
int end = scanner.nextInt();
treeZone.removeTrees(start, end);
}
System.out.println(treeZone.countRemainingTrees());
scanner.close();
}
}
三、P1068 分数线划定
洛谷链接: https://www.luogu.com.cn/problem/P1068
面向对象适配点: 封装"考生"为类,实现Comparable接口
import java.util.*;
class Candidate implements Comparable<Candidate> {
private int id;
private int score;
public Candidate(int id, int score) {
this.id = id;
this.score = score;
}
public int getId() { return id; }
public int getScore() { return score; }
@Override
public int compareTo(Candidate other) {
// 按分数降序,分数相同按学号升序
if (this.score != other.score) {
return other.score - this.score;
}
return this.id - other.id;
}
@Override
public String toString() {
return id + " " + score;
}
}
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int m = scanner.nextInt();
List<Candidate> candidates = new ArrayList<>();
for (int i = 0; i < n; i++) {
int id = scanner.nextInt();
int score = scanner.nextInt();
candidates.add(new Candidate(id, score));
}
Collections.sort(candidates);
int interviewCount = (int)(m * 1.5);
int scoreLine = candidates.get(interviewCount - 1).getScore();
// 统计实际进入面试的人数
int actualCount = 0;
for (Candidate c : candidates) {
if (c.getScore() >= scoreLine) {
actualCount++;
}
}
System.out.println(scoreLine + " " + actualCount);
for (int i = 0; i < actualCount; i++) {
System.out.println(candidates.get(i));
}
scanner.close();
}
}
四、P1093 奖学金
洛谷链接: https://www.luogu.com.cn/problem/P1093
面向对象适配点: 封装学生对象,自定义比较器(经典OOP排序题)
import java.util.*;
class Student implements Comparable<Student> {
private int id;
private int chinese;
private int math;
private int english;
private int total;
public Student(int id, int chinese, int math, int english) {
this.id = id;
this.chinese = chinese;
this.math = math;
this.english = english;
this.total = chinese + math + english;
}
public int getId() { return id; }
public int getChinese() { return chinese; }
public int getTotal() { return total; }
@Override
public int compareTo(Student other) {
// 按总分降序
if (this.total != other.total) {
return other.total - this.total;
}
// 总分相同按语文降序
if (this.chinese != other.chinese) {
return other.chinese - this.chinese;
}
// 总分和语文都相同按学号升序
return this.id - other.id;
}
@Override
public String toString() {
return id + " " + total;
}
}
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
List<Student> students = new ArrayList<>();
for (int i = 1; i <= n; i++) {
int chinese = scanner.nextInt();
int math = scanner.nextInt();
int english = scanner.nextInt();
students.add(new Student(i, chinese, math, english));
}
Collections.sort(students);
// 输出前5名
for (int i = 0; i < Math.min(5, students.size()); i++) {
System.out.println(students.get(i));
}
scanner.close();
}
}
五、P1603 斯诺登的密码
洛谷链接: https://www.luogu.com.cn/problem/P1603
面向对象适配点: 封装单词-数字映射类
import java.util.*;
class WordToNumber {
private static final Map<String, Integer> wordMap = new HashMap<>();
static {
// 初始化单词到数字的映射
wordMap.put("one", 1); wordMap.put("two", 4); wordMap.put("three", 9);
wordMap.put("four", 16); wordMap.put("five", 25); wordMap.put("six", 36);
wordMap.put("seven", 49); wordMap.put("eight", 64); wordMap.put("nine", 81);
wordMap.put("ten", 0); wordMap.put("eleven", 21); wordMap.put("twelve", 44);
wordMap.put("thirteen", 69); wordMap.put("fourteen", 96); wordMap.put("fifteen", 25);
wordMap.put("sixteen", 56); wordMap.put("seventeen", 89); wordMap.put("eighteen", 24);
wordMap.put("nineteen", 61); wordMap.put("twenty", 0); wordMap.put("a", 1);
wordMap.put("both", 4); wordMap.put("another", 1); wordMap.put("first", 1);
wordMap.put("second", 4); wordMap.put("third", 9);
}
private List<Integer> numbers;
public WordToNumber(String input) {
numbers = new ArrayList<>();
processInput(input);
}
private void processInput(String input) {
String[] words = input.toLowerCase().split("\\s+|[.]");
for (String word : words) {
if (wordMap.containsKey(word)) {
int num = wordMap.get(word);
numbers.add(num);
}
}
}
public String getPassword() {
if (numbers.isEmpty()) {
return "0";
}
// 将数字转换为两位数格式并排序
List<String> formattedNumbers = new ArrayList<>();
for (int num : numbers) {
formattedNumbers.add(String.format("%02d", num));
}
Collections.sort(formattedNumbers);
// 拼接成密码
StringBuilder password = new StringBuilder();
for (String numStr : formattedNumbers) {
password.append(numStr);
}
// 移除前导零
String result = password.toString();
while (result.length() > 1 && result.charAt(0) == '0') {
result = result.substring(1);
}
return result;
}
}
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String input = scanner.nextLine();
WordToNumber converter = new WordToNumber(input);
System.out.println(converter.getPassword());
scanner.close();
}
}
六、P3741 honoka的键盘
洛谷链接: https://www.luogu.com.cn/problem/P3741
面向对象适配点: 封装键盘状态对象进行字符串操作
面向对象设计思路
-
类设计:创建VKStringOptimizer类,封装字符串数据和相关操作方法。
-
封装性:将字符串长度、字符串内容以及核心算法封装在类内部,通过公共方法提供接口。
-
算法逻辑:
• 先计算原始字符串中不重叠的VK出现次数。• 尝试改变每个位置的字符(V↔K),计算新字符串的VK出现次数,取最大值。
• 由于字符串长度n ≤ 100,直接模拟可行。
import java.util.Scanner;
/**
* VK字符串优化器类
* 用于计算通过改变至多一个字符后,字符串中VK出现的最大次数
*/
class VKStringOptimizer {
private int n;
private String str;
/**
* 构造函数
* @param n 字符串长度
* @param str 字符串内容
*/
public VKStringOptimizer(int n, String str) {
this.n = n;
this.str = str;
}
/**
* 计算字符串中不重叠VK出现的次数
* @param s 输入字符串
* @return VK出现次数
*/
private int countVK(String s) {
int count = 0;
char[] arr = s.toCharArray();
for (int i = 0; i < arr.length - 1; i++) {
if (arr[i] == 'V' && arr[i + 1] == 'K') {
count++;
i++; // 跳过下一个字符,避免重叠计数
}
}
return count;
}
/**
* 计算最大可能的VK出现次数
* @return 最大次数
*/
public int calculateMaxVK() {
int baseCount = countVK(str); // 原始VK数量
int maxCount = baseCount;
// 如果字符串长度为1,无法形成VK,直接返回
if (n <= 1) {
return 0;
}
// 尝试改变每个位置的字符
char[] arr = str.toCharArray();
for (int i = 0; i < n; i++) {
// 保存原字符
char originalChar = arr[i];
// 改变字符:V->K 或 K->V
if (originalChar == 'V') {
arr[i] = 'K';
} else {
arr[i] = 'V';
}
// 构建新字符串并计算VK数量
String newStr = new String(arr);
int newCount = countVK(newStr);
maxCount = Math.max(maxCount, newCount);
// 恢复原字符
arr[i] = originalChar;
}
return maxCount;
}
}
/**
* 主程序类
*/
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
String s = scanner.next();
// 创建VK优化器对象
VKStringOptimizer optimizer = new VKStringOptimizer(n, s);
int result = optimizer.calculateMaxVK();
System.out.println(result);
scanner.close();
}
}
代码说明
-
VKStringOptimizer类:
• 属性:n(字符串长度)和str(字符串内容)。• 方法:
◦ countVK(String s):计算给定字符串中不重叠VK的出现次数。
◦ calculateMaxVK():通过改变至多一个字符,计算VK的最大出现次数。
-
主类Main:处理输入输出,创建优化器对象并调用方法。
-
算法细节:
• 遍历字符串时跳过已匹配的字符,避免重叠计数。• 改变字符后恢复原状,确保每次尝试独立。
测试样例验证
• 输入 #1:2 VK → 输出 1(原始已有VK)
• 输入 #2:2 VV → 输出 1(改变第二个V为K,得到VK)
• 输入 #3:1 V → 输出 0(长度不足)
• 输入 #4:20 VKKKKKKKKKVVVVVVVVVK → 输出 3
• 输入 #5:4 KVKV → 输出 1
该方法通过面向对象封装,清晰且易于扩展,时间复杂度为O(n²),在题目约束下高效可行。
面向对象设计特点总结:
- 封装性:每个类都将数据和操作封装在一起
- 单一职责:每个类负责一个明确的职责
- 方法封装:将逻辑操作封装为类的方法
- Comparable接口:在需要排序的题目中实现标准接口
- 数据隐藏:使用private修饰属性,提供getter方法
- 静态初始化块:在WordToNumber类中使用static块初始化映射表
- 构造方法:每个类都有适当的构造方法来初始化对象状态
这些题解既解决了算法问题,又体现了面向对象的设计思想,适合作为OOP入门练习。每道题都展示了不同的面向对象编程技巧,从简单的Calculator类到复杂的映射处理类,涵盖了OOP的基础概念。

浙公网安备 33010602011771号