英雄会(csdn pongo)题解之求导数

这道题很简单,从题目中给出的几种倒数的求法和我们对求导的理解,得出通过递归即能求解,写这篇博客的目的是感觉这道题描述不是很好,尤其是里面有句"输入保证合法。注意要带着括号",让我以为测试用例中没有像((((x)*(x))))这样外面有多余的括号的情况,而测试用例里面竟有这样的,这时需要将最外面的多余括号保留到最终的求导结果中,所以写这篇博客,为了减少大家在测试用例上浪费的时间,还有从题目中可以看出,求导时同级运算具有右结合性(即先算右边的),即如(x*x*x)'=(1*x*x+x*{x*x}') ,这里用花括号的目的是说明此对括号不是本身字符串里面的。

题目详情:

根据导数公式求导数

(a + b)' = a' + b'

(a - b)' = a' - b'

(a * b)' = (a' * b + a * b')

(a / b)' = (a' * b - a * b') / b^2

ln(a)' = (a')/(a)

x' = 1

const' = 0

输入保证合法。注意要带着括号,注意不要优化,例如 0*a不能写成0, 1*a也不能写成a。详见样例。

输入格式

每行一个多项式

输出格式

每行一个多项式,对应多项式的导数


答题说明:

输入样例

x*x/x

-45.78*x+x

-2.45*x*x+ln(x-3)

输出样例

((1*x+x*1)*x-x*x*1)/x^2

(0*x-45.78*1)+1

((0*x-2.45*1)*x-2.45*x*1)+(1-0)/(x-3)


友情提醒:

1、本题用OJ模式答题,答题时可把下面输入框内预留的函数全部直接去掉,自己另起函数名实现本题功能。

我的解法,其实上面基本已经说出了我的做法,这里补充下:

首先将表达式的外层无用括号去掉(返回结果时再添加上),然后尝试将表达式以+,-,*,/将其分割成左右两个子表达式,什么样的算术运算符能将表达式分割成两个子表达式呢,显然是不在括号里面的算术运算符,还有+ - 的分割优先级高于* /,同优先级具有右结合性,然后按照求导规则对左右分别求导,返回结果;如果不能将其分割成两个子表达式,那么这是对表达式按ln对数求导。

需要注意:1.最外层的多余括号;2.右结合性

代码如下:

#include<iostream>
#include<string>
//统计str最外层的括号对数,如:(((x)*(x)*5))为2
int getOutBrackets(const std::string&str){
    int max=0;//最外层最多有几对括号
    for(int i=0;i<str.size()/2;++i)
        if(str[i]=='('&&str[str.size()-i-1]==')')
            ++max;
        else break;
    int lBracket=0;
    int end=str.size()-max;
    for(int i=max;i<end;++i)
        if(str[i]!='('&&str[i]!=')')
            continue;
        else if(str[i]=='(')
            ++lBracket;
        else if(lBracket==0)
            --max;
        else
            --lBracket;      
    return max;
}
std::string diff(std::string&str){
    int out=getOutBrackets(str);
    if(out>0)
        return str.substr(0,out)+diff(str.substr(out,str.size()-2*out))+str.substr(str.size()-out,out);
    if(std::string::npos==str.find('x'))
        return "0";    
    else if(1==str.size()&&'x'==str[0])
        return "1";
    else{//size>=2, str contains x    
		int hasR=0;//右括号的数量
        int pos[4]={0,0,0,0};//begin with 1
		//题目中看出是求导时的右结合性,所以从后向前遍历
        std::string::size_type i=str.size()-1;
        for(;i>=1;--i){
            if('0'<=str[i]&&'9'>=str[i]||'.'==str[i]||'l'==str[i]||'n'==str[i]||'x'==str[i])
                continue;
            if(str[i]==')')
				++hasR;
            else if(str[i]=='(')
			   --hasR;
            else if(str[i]=='+'){
                if(!hasR){
                    pos[0]=i;
                    break;
                }
            }else if(str[i]=='-'){
                if(!hasR){
                    pos[1]=i;
                    break;
                }
            }else if(str[i]=='*'){
                if(!hasR&&i>pos[2])
                    pos[2]=i;       
            }else if(!hasR&&i>pos[3])
                pos[3]=i;         
        }
        if(pos[0]>0)
            return diff(str.substr(0,pos[0]))+'+'+diff(str.substr(pos[0]+1));
        else if(pos[1]>0)
            return diff(str.substr(0,pos[1]))+'-'+diff(str.substr(pos[1]+1));    
        else if(pos[2]>pos[3]){
            std::string left=str.substr(0,pos[2]);
            std::string right=str.substr(pos[2]+1);
            if('-'==left[0])
                return '('+diff(left)+'*'+right+left+'*'+diff(right)+')';
            else 
                return '('+diff(left)+'*'+right+'+'+left+'*'+diff(right)+')';
        }else if(pos[2]<pos[3]){
            std::string left=str.substr(0,pos[3]);
            std::string right=str.substr(pos[3]+1);
            return '('+diff(left)+'*'+right+'-'+left+'*'+diff(right)+")/"+right+"^2";
        }else{
            std::string left=str.substr(3,str.size()-4);
            return '('+diff(left)+")/"+'('+left+')';
        }
    }
}
int main(int argc,char** argv){
    std::string str,d;;
    while(std::cin>>str)   
        std::cout<<diff(str)<<std::endl;
    return EXIT_SUCCESS;
}




评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值