写在前面:翻看以前做的程设题,偶然看到这个期末考没做出来的硬茬(当时是一元一次求根),重新写了个升级版,弥补一下遗憾。
力扣题库“求解方程”可过,改一下函数名即可。
目录
格式控制
考虑到力扣里面有一个情况是“0x=0”,系数可以是0,还有输出的时候若根是整数应该不带小数点,代码进行了整型判断,控制了格式。
输入格式
系数写在x前面,若是分数则按"分子/分母"形式写,x后面只可有两种数字,1或2,分别代表一次幂和二次幂,不写就默认一次幂。
输入格式具有包容性,是利用string实现的,比如"0/4x2+32x1-x-0+1-1/1=+55-22+33-4/2x"这样写也可以,简化后就是"33x-66=0"此时只有一解是x=2。
暂不支持括号()和乘*运算,除/运算也只支持系数和常数,系数及常数不支持超大数,欢迎小伙伴们提提点子。
输出格式
若二次项系数为0,则输出"x=...",不为0,输出"x1=... x2=...",可以在函数后面找return修改输出格式。"No solution"表示无解,"Infinite solutions"表示有无穷解。
可修改:若输入规范,比如只输入a(二次项系数),b(一次项系数),c(常数项),代码将num1赋值b,num2赋值a,num3赋值c即可,函数里的符号判断都可去掉。
系数获取
按位读取string s,把数存进temp,考虑符号。设置fu1判断前面符号是“+”还是“-”,fu2判断读取位置的等式左右,右边统一*-1来实现将右式移到左边计算。读取时前一位也是数字便将保存的值*10再进行相加,以实现保存多位数字。加入flag判断是否出现分数,若有则保存分子值到save,再除以分号后分母的值,然后将分数的值存进temp中。
if (isdigit(*(p + i))) {
if (!i)temp += *(p + i) - '0';
else if (!isdigit(*(p + i - 1))) {
temp += (*(p + i) - '0') * fu1 * fu2;
if (!isdigit(s[i+1]) && flag) {
temp = save / temp;
save = 0;
flag = 0;
}
}
else {
temp = temp * 10 + (*(p + i) - '0') * fu1 * fu2; //移位后加的数也要考虑符号
if (!isdigit(s[i+1]) && flag) {
temp = save / temp;
save = 0;
flag = 0;
}
}
}
else if (*(p + i) == 'x') {
if (s[i+1] == '2') { //考虑2次,越界问题有'\0'不怕
if (!i)num2 = 1;
else if (!isdigit(*(p + i - 1)))num2 += fu1 * fu2; //怕系数是0,cornercase
else {
num2 += temp;
temp = 0;
}
i++;
}
else { //1次
if (!i)num1 = 1;
else if (!isdigit(*(p + i - 1)))num1 += fu1 * fu2; //怕系数是0
else {
num1 += temp;
temp = 0;
}
if (s[i + 1] == '1')i++; //考虑1次幂
}
}
可以看到,当读到“x”,经判断后将temp值累加到相应次数项的系数中,num1、num2分别保存一次项、二次项系数。
符号判断
else if (*(p + i) == '=') { //符号变,temp清零
if (temp)num3 += temp;
fu1 = 1;
fu2 = -1;
temp = 0;
}
else if (*(p + i) == '-') {
if (temp)num3 += temp;
fu1 = -1;
temp = 0;
}
else if (*(p + i) == '+') {
if (temp)num3 += temp;
fu1 = 1;
temp = 0;
}
else if (*(p + i) == '/') { //考虑分数
save = fabs(temp);
temp = 0;
flag = 1;
}
}
num3 += temp;
每次读到符号,除了符号的改变,若temp值没有保存到各项系数中,则累加至常数项num3,注意末尾要再加一次。
根的计算
二次项系数为0,则变为解一元一次方程,只返回“x=...”,计算只需-num3/num1即可,对结果加入了精确到小数点后六位的整形判断,如果是整数解,则不带小数点规范输出。
二次项系数不为0,有两解,利用求根公式,返回“x1=... x2=...",对结果加入了精确到小数点后六位的整形判断,如果是整数解,则不带小数点规范输出。
if (num2 == 0) { //2次项系数为0情况
if (!num1 && num3)return "No solution"; //无解
else if (!num1 && !num3)return "Infinite solutions"; //无穷解
else
if (fabs(fabs(num3 / num1) - int(fabs(num3 / num1) + 0.5)) < 0.000001) { //判断能否用整数表示答案
int x, flag1 = 1; //符号判断
if (-num3 / num1 < 0)flag1 = -1;
x = int(fabs(num3 / num1) + 0.5)*flag1;
return "x=" + to_string(x);
}
else return "x=" + to_string(-num3 / num1);
}
else {
double delta = num1 * num1 - 4 * num2 * num3;
if (delta < 0)return "No solution";
else {
double x1 = (-num1 + sqrt(delta)) / (2 * num2), x2 = (-num1 - sqrt(delta)) / (2 * num2); //求根公式
if (fabs(fabs(x1) - int(fabs(x1) + 0.5)) < 0.000001 && fabs(fabs(x2) - int(fabs(x2) + 0.5)) < 0.000001) { //判断能否用整数表示答案
int tx1, tx2, flag2 = 1, flag3 = 1; //符号判断
if (x1 < 0)flag2 = -1;
if (x2 < 0)flag2 = -1;
tx1 = int(fabs(x1) + 0.5) * flag2;
tx2 = int(fabs(x2) + 0.5) * flag3;
return "x1=" + to_string(tx1) + " x2=" + to_string(tx2);
}
else return "x1=" + to_string(x1) + " x2=" + to_string(x2);
}
}
源码及注释
#include <iostream>
#include <string>
#include <cmath>
using namespace std;
string Solution(string& s) {
string::iterator p = s.begin(), end = s.end();
double temp = 0, num1 = 0, num2 = 0, num3 = 0; //num1是一次系数,2是二次,3常数,temp作为暂时数
int flag = 0, save = 0, fu1 = 1, fu2 = 1;//flag判断有无分数,save保存分子,fu1判断符号,fu2判断等式左右,右边统一换号
for (int i = 0; p + i != end; i++) {
if (isdigit(*(p + i))) {
if (!i)temp += *(p + i) - '0';
else if (!isdigit(*(p + i - 1))) {
temp += (*(p + i) - '0') * fu1 * fu2;
if (!isdigit(s[i+1]) && flag) {
temp = save / temp;
save = 0;
flag = 0;
}
}
else {
temp = temp * 10 + (*(p + i) - '0') * fu1 * fu2; //移位后加的数也要考虑符号
if (!isdigit(s[i+1]) && flag) {
temp = save / temp;
save = 0;
flag = 0;
}
}
}
else if (*(p + i) == 'x') {
if (s[i+1] == '2') { //考虑2次,越界问题有'\0'不怕
if (!i)num2 = 1;
else if (!isdigit(*(p + i - 1)))num2 += fu1 * fu2; //考虑系数可能是0
else {
num2 += temp;
temp = 0;
}
i++;
}
else { //1次项系数处理
if (!i)num1 = 1;
else if (!isdigit(*(p + i - 1)))num1 += fu1 * fu2; //考虑系数可能是0
else {
num1 += temp;
temp = 0;
}
if (s[i + 1] == '1')i++; //考虑1次幂
}
}
else if (*(p + i) == '=') { //遇"="符号变,temp清零
if (temp)num3 += temp;
fu1 = 1;
fu2 = -1;
temp = 0;
}
else if (*(p + i) == '-') {
if (temp)num3 += temp;
fu1 = -1;
temp = 0;
}
else if (*(p + i) == '+') {
if (temp)num3 += temp;
fu1 = 1;
temp = 0;
}
else if (*(p + i) == '/') { //考虑分数
save = fabs(temp);
temp = 0;
flag = 1;
}
}
num3 += temp;
if (num2 == 0) { //只有1次项情况
if (!num1 && num3)return "No solution"; //无解
else if (!num1 && !num3)return "Infinite solutions"; //无穷解
else
if (fabs(fabs(num3 / num1) - int(fabs(num3 / num1) + 0.5)) < 0.000001) { //判断能否用整数表示答案
int x, flag1 = 1; //符号判断
if (-num3 / num1 < 0)flag1 = -1;
x = int(fabs(num3 / num1) + 0.5)*flag1;
return "x=" + to_string(x);
}
else return "x=" + to_string(-num3 / num1);
}
else {
double delta = num1 * num1 - 4 * num2 * num3;
if (delta < 0)return "No solution";
else {
double x1 = (-num1 + sqrt(delta)) / (2 * num2), x2 = (-num1 - sqrt(delta)) / (2 * num2); //求根公式
if (fabs(fabs(x1) - int(fabs(x1) + 0.5)) < 0.000001 && fabs(fabs(x2) - int(fabs(x2) + 0.5)) < 0.000001) { //判断能否用整数表示答案
int tx1, tx2, flag2 = 1, flag3 = 1; //符号判断
if (x1 < 0)flag2 = -1;
if (x2 < 0)flag2 = -1;
tx1 = int(fabs(x1) + 0.5) * flag2;
tx2 = int(fabs(x2) + 0.5) * flag3;
return "x1=" + to_string(tx1) + " x2=" + to_string(tx2);
}
else return "x1=" + to_string(x1) + " x2=" + to_string(x2);
}
}
}
int main() {
string s;
cin >> s;
cout << Solution (s);
return 0;
}
欢迎大家进行测试,若能指出其中错误或可优化处十分感激,你们的反馈就是我创作的动力。