解一元一次方程的那些坑(记洛谷P1022题RE的经历)
important!!!
遇到RE不可怕,纯粹的RE还行(后面没有WA的话,可能你的算法本身没错)。
这固然会使得我们困惑,但我们只需要记得最常见的几种RE,加以分析,给一些脑洞大的测试样例就一般可以测出隐藏的语法Bug。。。
空指针还好吧,在OJ里的大问题不是空指针,一般是NumberFormatException或者越界的异常等等………………自己去测测,必有惊喜,必有福报~~
终于做了一个黄题,Nice!!!
题目要求
分析
其实就是拿过来一个一元一次方程然后求解。。。
问题是,坑是真多。。下面分享几个。。。。
- 首先是你得处理符号,因为比如说“-”即是减号也是负号,“+”只代表加号(我们不会在正数前面加+)。
- 接下来你要注意怎么去split到数据,如果你不想逐个处理,可以分治,先按照“=”切分为左右两部分字符串,然后左右分别按照“+”或者“-”切分。(正则为
"[+]|[-]"
) - 然后你得注意开头的符号要消去,不要直接split导致出现"",这是糟糕的情况,会RE。(比如“-2x+2=3”)
- 还有就是你得知道:-0.0000000000001这样的数在截出来以后是-0.000,这不能被OJ接收。。。
- 接着上面一条说,另外非常恶心的是,-0.0/2得到的是-0.000(保留三位小数),这个-0.000其实按照我们补码理论是不存在的,它的存在就很恶心,在jshell里测试的时候就是与0.000相等的(包括与0相等)。其实一样,但你放OJ里就gg了,是不行的。。。
- ……
第一次提交——WA+RE
这个WA的比较弱智,因为没注意输出格式。。。
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String expression = scanner.nextLine();
scanner.close();
//未知变量的表示(小写字母)
char x = 'x';
for (char c : expression.toCharArray()) {
if (c >= 'a' && c <= 'z') {
x = c;
break;
}
}
String[] expressionArr = expression.split("=");
boolean leftNeg = false, rightNeg = false;
String left = expressionArr[0], right = expressionArr[1];
if (left.startsWith("-")) {
leftNeg = true;
left = left.substring(1, left.length());
}
if (right.startsWith("-")) {
rightNeg = true;
right = right.substring(1, right.length());
}
Queue<Character> leftCharacters = new LinkedList<>();
if (leftNeg) {
leftCharacters.offer('-');
} else {
leftCharacters.offer('+');
}
for(char c : left.toCharArray()) {
if (c == '+' || c == '-') {
leftCharacters.offer(c);
}
}
Queue<Character> rightCharacters = new LinkedList<>();
if (rightNeg) {
rightCharacters.offer('-');
} else {
rightCharacters.offer('+');
}
for(char c : right.toCharArray()) {
if (c == '+' || c == '-') {
rightCharacters.offer(c);
}
}
String[] leftArr = left.split("[+]|[-]"), rightArr = right.split("[+]|[-]");
int leftCounter = 0, leftCoefficient = 0, rightCounter = 0, rightCoefficient = 0;
outer:
for (String leftObj : leftArr) {
char[] chars = leftObj.toCharArray();
char sign = leftCharacters.poll();
for (char c : chars) {
if (c == x) {
leftObj = leftObj.substring(0, leftObj.length()-1);
leftCoefficient += Integer.parseInt(sign+leftObj);
continue outer;
}
}
//不是未知量
leftCounter += Integer.parseInt(sign+leftObj);
}
outer:
for (String rightObj : rightArr) {
char[] chars = rightObj.toCharArray();
char sign = rightCharacters.poll();
for (char c : chars) {
if (c == x) {
rightObj = rightObj.substring(0, rightObj.length()-1);
rightCoefficient += Integer.parseInt(sign+rightObj);
continue outer;
}
}
//不是未知量
rightCounter += Integer.parseInt(sign+rightObj);
}
System.out.printf("%.3f", ((double)(rightCounter-leftCounter))/(leftCoefficient-rightCoefficient));
}
}
第二次提交——RE
第二次RE了,平时测试没问题,但就很不解。。。
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String expression = scanner.nextLine();
scanner.close();
//未知变量的表示(小写字母)
char x = 'x';
for (char c : expression.toCharArray()) {
if (c >= 'a' && c <= 'z') {
x = c;
break;
}
}
String[] expressionArr = expression.split("=");
boolean leftNeg = false, rightNeg = false;
String left = expressionArr[0], right = expressionArr[1];
if (left.startsWith("-")) {
leftNeg = true;
left = left.substring(1, left.length());
}
if (right.startsWith("-")) {
rightNeg = true;
right = right.substring(1, right.length());
}
Queue<Character> leftCharacters = new LinkedList<>();
if (leftNeg) {
leftCharacters.offer('-');
} else {
leftCharacters.offer('+');
}
for(char c : left.toCharArray()) {
if (c == '+' || c == '-') {
leftCharacters.offer(c);
}
}
Queue<Character> rightCharacters = new LinkedList<>();
if (rightNeg) {
rightCharacters.offer('-');
} else {
rightCharacters.offer('+');
}
for(char c : right.toCharArray()) {
if (c == '+' || c == '-') {
rightCharacters.offer(c);
}
}
String[] leftArr = left.split("[+]|[-]"), rightArr = right.split("[+]|[-]");
int leftCounter = 0, leftCoefficient = 0, rightCounter = 0, rightCoefficient = 0;
outer:
for (String leftObj : leftArr) {
char[] chars = leftObj.toCharArray();
char sign = leftCharacters.poll();
for (char c : chars) {
if (c == x) {
leftObj = leftObj.substring(0, leftObj.length()-1);
leftCoefficient += Integer.parseInt(sign+leftObj);
continue outer;
}
}
//不是未知量
leftCounter += Integer.parseInt(sign+leftObj);
}
outer:
for (String rightObj : rightArr) {
char[] chars = rightObj.toCharArray();
char sign = rightCharacters.poll();
for (char c : chars) {
if (c == x) {
rightObj = rightObj.substring(0, rightObj.length()-1);
rightCoefficient += Integer.parseInt(sign+rightObj);
continue outer;
}
}
//不是未知量
rightCounter += Integer.parseInt(sign+rightObj);
}
System.out.print(x + "=");
System.out.printf("%.3f", ((double)(rightCounter-leftCounter))/(leftCoefficient-rightCoefficient));
}
}
自检过程
其实试了很多,都没问题,于是就开一个大数,,,
先是尝试了大数,被爆了NumberFormatException,如我所料,题没限制范围,就改为long保保险。。
但还是这样:所以就意识到一个巨大的思维差别:我们写的一元一次方程一般+x这样就OK,但我们的程序只能直接认识+1x,这就得我们再分出一种情况讨论。。。
然后继续,还是异常RE:
就是分析部分分析到的-0.000的问题,我们应该让它输出0.000,这就要求必须在上面操作。
偏偏这个数不是0.000(因为这是截出来的,我们在上面judge的是原数,所以是大于-0.0005而不能变成-0.001的数值,是负数,所以处理一下就OK)
第三次提交——RE(好一些了,就剩一个RE了)
这次纯属智障行为,因为左边改了,右边没改,这点一定要注意!!!
不要犯这种无脑错。。。
代码不放了,显得智障。。。
第四次提交——AC
写的比较冗长,不是很好。。也没抽出来函数,直接main到底、。。。。
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String expression = scanner.nextLine();
scanner.close();
//未知变量的表示(小写字母)
char x = 'x';
for (char c : expression.toCharArray()) {
if (c >= 'a' && c <= 'z') {
x = c;
break;
}
}
String[] expressionArr = expression.split("=");
boolean leftNeg = false, rightNeg = false;
String left = expressionArr[0], right = expressionArr[1];
if (left.startsWith("-")) {
leftNeg = true;
left = left.substring(1, left.length());
}
if (right.startsWith("-")) {
rightNeg = true;
right = right.substring(1, right.length());
}
Queue<Character> leftCharacters = new LinkedList<>();
if (leftNeg) {
leftCharacters.offer('-');
} else {
leftCharacters.offer('+');
}
for(char c : left.toCharArray()) {
if (c == '+' || c == '-') {
leftCharacters.offer(c);
}
}
Queue<Character> rightCharacters = new LinkedList<>();
if (rightNeg) {
rightCharacters.offer('-');
} else {
rightCharacters.offer('+');
}
for(char c : right.toCharArray()) {
if (c == '+' || c == '-') {
rightCharacters.offer(c);
}
}
String[] leftArr = left.split("[+]|[-]"), rightArr = right.split("[+]|[-]");
long leftCounter = 0, leftCoefficient = 0, rightCounter = 0, rightCoefficient = 0;
outer:
for (String leftObj : leftArr) {
char[] chars = leftObj.toCharArray();
char sign = leftCharacters.poll();
for (char c : chars) {
if (c == x) {
leftObj = leftObj.substring(0, leftObj.length()-1);
if ("".equals(leftObj)) {
leftCoefficient++;
} else {
leftCoefficient += Long.parseLong(sign+leftObj);
}
continue outer;
}
}
//不是未知量
leftCounter += Long.parseLong(sign+leftObj);
}
outer:
for (String rightObj : rightArr) {
char[] chars = rightObj.toCharArray();
char sign = rightCharacters.poll();
for (char c : chars) {
if (c == x) {
rightObj = rightObj.substring(0, rightObj.length()-1);
if ("".equals(rightObj)) {
rightCoefficient++;
} else {
rightCoefficient += Long.parseLong(sign+rightObj);
}
continue outer;
}
}
//不是未知量
rightCounter += Long.parseLong(sign+rightObj);
}
double result = ((double)(rightCounter-leftCounter))/(leftCoefficient-rightCoefficient);
if (result > -0.0005 && result < 0) {
System.out.printf("%c=%.3f", x, 0.000);
} else {
System.out.printf("%c=%.3f", x, result);
}
}
}
庆祝一下:
上一篇: 【NOIP】计算器的改良
下一篇: JVM如何判断对象是否可以被回收