💻 CSC1003 期末总结
Some Indonesian bro I knew for a while told me yesterday that he is a native Javanese people and speaks Java as his mother tongue. Astonished by this fact, I answered him:
import java.util.*; import java.io.*; import java.util.concurrent.*; import java.util.function.*; public class MotherTongue { public static void main(String[] args) { System.out.println("Wait, you speak Java natively? No wonder you got full marks in CS. That's way too OP, man."); } }
CSC Final
字符串的处理
a.replace(b, c)
-
a.replace(b, c)会将一个字符串 a 里的所有字符串 b 替换为 c。也可以直接去除 b,或者在每两个字符间加一个 c。 -
适用于字符和字符串。
-
例如,去除单词间的空格:
"Hello world".replace(" ", ""); -
应用:OJ 习题P1019 (BanishLetter2)
Write a static method that takes a String and many char values. Delete all the characters in the String that equals to the char values, and return the result. For example:
Input: Output:
Hello World He Wrd
o l k
- 确实,我们可以逐个检验字符串,并过滤要求的字母:
import java.util.Scanner;
public class BanishLetter2 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String in = sc.nextLine();
String filterset = sc.nextLine();
String[] input = in.split("");
String[] filter = filterset.split(" ");
next:
for (int i=0; i<input.length; i++) {
for (int j=0; j<filter.length; j++) {
if (filter[j].equals(input[i])) continue next;
}
System.out.print(input[i]);
}
System.out.println();
}
}
- 但使用 replace 方法可以不把目标字符串拆成数组,直接处理:
import java.util.Scanner;
public class BanishLetter2 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String input = sc.nextLine();
String filterset = sc.nextLine();
String[] filter = filterset.split(" ");
for (int i=0; i<filter.length; i++) input = input.replace(filter[i], "");
System.out.println(input);
}
}
a.startWith(b) 和 a.endWith(c)
-
判断 a 字符一开始是否包含某个字符串 b; 判断 a 字符一开始是否包含某个字符串 c。
-
应用:OJ 习题P1015 (Longest Common Prefix)
Write a static method that takes a String array and return the longest common prefix. Return an empty String if common prefix does not exist.
Input1:
flower flow flightOutput1:
flInput2:
hello world csc1003Output2:
-
思路:通过假设第一个单词是 LCP ,只要余下的单词有一个不 startsWith 它,就把它最后一位字符去掉。如此循环知道其余所有单词每个都等于这个修剪后的 LCP。
import java.util.Scanner;
public class LCP {
public static String lcp(String[] strs) {
String prefix = strs[0]; // 先假设第一个单词是最长共同前缀
for (int i = 1; i < strs.length; i++) {
while (!strs[i].startsWith(prefix)) { //如果数组存在单词与默认前缀不相等,则缩短一位
prefix = prefix.substring(0, prefix.length() - 1);
if (prefix.isEmpty()) {
return "";
}
}
}
return prefix; //缩短到所有单词都满足被缩短过的第一个单词后,返回值 ·
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String input = sc.nextLine();
String[] words = input.split(" ");
String result = lcp(words);
System.out.println(result);
}
}
a.substring(b, c)
-
a.substring(b, c)可以把字符串 a 取出其中索引在[b, c)范围内的字符取出。也可以只取出a[b]。 -
例如,逐个 字母输出一个字符串:
String str = "Hello World" for (i=0; i=str.length; i++) { if (!str.substring(i, i+1).equals(" ")) { System.out.println(str.substring(i, i+1) } } -
应用:OJ 习题P1021 (Bool)
A Boolean expression is an expression that evaluates to either true or false. Valid expressions follow the following conventions:
the result of ’t’ is true; the result of ‘f’ is false; ‘!(subExpr)’ means to perform logical NOT operation on the internal expression subExpr; ‘&(subExpr1, subExpr2, …, subExprn)’ means to perform logical AND operation on 2 or more internal expressions subExpr1, subExpr2, …, subExprn; ‘|(subExpr1, subExpr2, …, subExprn)’ means to perform logical OR operation on 2 or more internal expressions subExpr1, subExpr2, …, subExprn.
Given a boolean expression in the form of a String, you need to return the result of the expression.
Input1: |(f,f,f,t) Input2: !(&(f,t)) Output1: t Output2: true -
这道题如果要把字符串变成数组然后循环数组来操作就过于麻烦;而且 substring 可以直接选中字符串中某一部分,而数组需要写循环甚至嵌套循环。
-
我的解法:方法检测到操作符(&, |)就去掉前后面的括号和所有逗号,然后递归这个处理后的字符串;检测到 “t”, “f” 就返回对应布尔值;检测到 “!” 就返回后面值的相反值。
import java.util.*;
public class Bool {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String expression = sc.nextLine();
System.out.println(evaluateExpr(expression));
}
public static boolean evaluateExpr(String expr) {
// 处理括号内的 f 和 t
if (expr.equals("t")) return true;
if (expr.equals("f")) return false;
// 所有的 return 都会把信息返还给调用函数处,所以递归时使用 return 不会结束函数
if (expr.startsWith("!")) {
return !evaluateExpr(expr.substring(2, expr.length() - 1)); // 去掉前后括号
}
if (expr.startsWith("&")) {
String innerExprs = filter(expr.substring(2, expr.length() - 1));
for (int i=0; i<innerExprs.length(); i++) {
if (!evaluateExpr(innerExprs.substring(i, i+1))) return false;
// AND 操作只要有一个 f 就是 false
}
return true;
}
if (expr.startsWith("|")) {
String innerExprs = filter(expr.substring(2, expr.length() - 1));
for (int i=0; i<innerExprs.length(); i++) {
if (evaluateExpr(innerExprs.substring(i, i+1))) return true;
// OR 操作只要有一个 t 就是 true
}
return false;
}
return true; //这里的 return 值无所谓,因为输入信息符合要求时,代码不可能运行到这里
}
public static String filter(String expr) {
String split = expr.replace(",", "");
return split;
}
}
a.contains(Char b)
- 判断 a 字符串是否包含 b 字符,返回 true 或 false。一般会用在判断语句中作为 if 或 while 的条件。
a.IndexOf(Char b)和 a.IndexOf(String b)
- 类似于上面一种,但是可以处理字符串,会指出字符(串) b 首次出现在 a 的哪里,返回值是 Int 类型。
- 如果用于判断 a 中是否含有 b 字符(串),只需要判断返回值是否为 -1。
易错用法
a.length 和 a.length()
a.length用于 a 为一个数组时返回长度,a.length()则用于 a 为一个字符串时,两者无法混用。- 数组和字符串都是数据类型。数组的长度显然是其成员变量,而字符串的长度是一个方法。
(<type>) b 和 Integer.parseInt(b)
- 强制转换
type a = (type) b只能用于数字类型(long, short, int, String…)相互转化,一般用于取整:。
关于 return 和方法递归
- 很多人认为
return的作用是直接结束方法,并把返回调用方法处。实际上在递归时return并不会结束方法,而是返回上一次调用自己时的位置。 - 比如一个方法“recur(String a)",可以在 recur 方法中调用
return recur(String b) + recur(String c)完成复杂或拆解类递归操作,比如编程处理复杂计算式时,按运算符分解计算式,大而化小,小而化之。
OOP 和 DT
-
每当我们在 Java 中遇到
Class.b时就说明 b 是“Class“类一个成员变量,比如在定义类”Coffee“时,在类中声明public final foam;并在 Constructor:public Coffee(double foam)中声明this.foam = foam;即可调用 foam 变量:Coffee cappuccino = new Coffee(1/3); // 此处调用的正是构造方法 Constructer! double foampct = cappuccino.foam // foampct = 0.333333... -
更常见的 例子便是
array.length,其中 length 是 array(给定数组)的不可更改的成员变量。 -
注意:如果成员变量不是“final”(不可更改)的,那便不建议直接访问成员变量,而是要依靠 Getter 方法访问变量。这是为了维护类的封装的完整性。
-
关于 DT 的创建,Lecture 中的例子:
public class Complex { private final double re; private final double im; public Complex(double real, double imag) { this.re = real; this.im = imag; } public Complex plus(Complex b) { double real = this.re + b.re; double imag = this.im + b.im; return new Complex(real, imag); } public Complex times(Complex b) { double real = this.re * b.re - this.im * b.im; double imag = this.re * b.im + this.im * b.re; return new Complex(real, imag); } public double modulus() { return Math.sqrt(re * re + im * im); } // 测试代码 public static void main(String[] args) { Complex a = new Complex(3.0, 4.0); Complex b = new Complex(1.0, 2.0); System.out.println("a: " + a); System.out.println("b: " + b); System.out.println("a + b: " + a.plus(b)); System.out.println("a * b: " + a.times(b)); System.out.println("Modulus of a: " + a.modulus()); } }- 这是一个能接收并计算复数加法、乘法和膜的代码。
- 每次涉及到复数都需要调用构造方法。
- a.plus(b) 和 a.times(b) 中的 b 不可省略,因为声明方法时代码中的"b"跟实例化的"b"不是一个东西。