Оценить полиномиальную строку без использования регулярных выражений и API

Учитывая многочлен с одной переменной x и значением x в качестве входных данных, вычислите его значение. Примеры:

eval("-2x^3+10x-4x^2","3")=-60

eval("x^3+x^2+x","6")=258

Описание проблемы: в этом коде я разбиваю строку на подстроку всякий раз, когда встречается +/-, и передаю подстроку функции, которая оценивает один термин, например "-2x^3". Итак, мой код для ввода = "-2x^3+10x-4x^2" вычисляет только до "-2x^3+10x" и пропускает часть "-4x^2".

Кто-нибудь может сказать мне, что здесь не так?

public class EvalPolyX2 {

    static String testcase1 = "-2x^3+10x-4x^2";
    static String testcase2 = "3";

    public static void main(String args[]){
        EvalPolyX2 testInstance = new EvalPolyX2();
        int result = testInstance.eval(testcase1,testcase2);
        System.out.println("Result : "+result);
    }

    public int eval(String str,String valx){

        int sum = 0;        
        String subStr = "";
        if(str.charAt(0) == '-')
        {
            int len = str.length();
            for (int i = 0; i < len; i++)
            {
                if(str.charAt(i) == '-' || str.charAt(i) == '+')
                {                   
                    subStr = str.substring(0, i);
                    System.out.println("subStr="+subStr);
                    sum += evalSubPoly(subStr, valx);
                    str = str.substring(i);
                    len = str.length();
                    i = 0;
                }               
            }
        }
        else if(str.charAt(0) != '-')
        {
            str = '+' + str;
            int len = str.length();
            for (int i = 0; i < len; i++)
            {
                if(str.charAt(i) == '-' || str.charAt(i) == '+')
                {
                    subStr = str.substring(0, i);
                    System.out.println("subStr="+subStr);
                    sum += evalSubPoly(subStr, valx);
                    str = str.substring(i);
                    len = str.length();
                    i=0;
                }
            }
        }
        return sum;
    }

    public int evalSubPoly(String poly,String valx){
        int len = poly.length();
        String num = "";
        String power = "";
        int exp = 0, coeff = 0;

        for(int i = 0; i < len; i++)
        {
            if(poly.charAt(i) == 'x')
            {
                num = poly.substring(0, i);
                coeff = Integer.parseInt(num);                              
            }
            if(poly.charAt(i) == '^')
            {
                power = poly.substring(i+1, len);
                exp = Integer.parseInt(power);
            }                       
        }

        if(power.equals(""))
            exp = 1;
        System.out.println("coeff="+coeff);

        int sum = 1;
        int x = Integer.parseInt(valx);

        for (int i = 0; i < exp; i++)
        {
            sum = sum*x;
        }
        System.out.println("sum="+sum);
        sum = sum*coeff;

        return sum;
    }
}

person abhishek14d    schedule 22.08.2013    source источник
comment
Позвольте мне перефразировать: при попытке запустить пример кода как есть я получаю Exception in thread "main" java.lang.NumberFormatException: For input string: "+10". Это означает, что ваш пример кода не воспроизводит проблему, что усложняет нам жизнь.   -  person Bernhard Barker    schedule 22.08.2013
comment
Дюклин прав, потому что вы включаете знак +/- в строку после того, как нашли ее. Чтобы избежать этого, вам нужно изменить str = str.substring(i); на str = str.substring(i+1); таким образом, чтобы остальная часть строки начиналась после +/-, а не включала его.   -  person Paris Nelson    schedule 22.08.2013
comment
Но разве ему не нужно включать это, если это «-»? В противном случае тот факт, что это «-», а не «+», полностью теряется.   -  person ajb    schedule 22.08.2013


Ответы (6)


Эта замена кода должна помочь

  if(str.charAt(i) == '-' || str.charAt(i) == '+' || i == (len - 1))
  {   
    if(i == len - 1)
    {
     i++;
    }
    ...

Хотя могли быть и лучшие пути, но я хотел только показать выход здесь. Причина в том, что вы ищете + или - в качестве разделителя. Но последняя часть выражения не будет заканчиваться ни одним из них, а просто, вероятно, EOL

person Shiva Kumar    schedule 22.08.2013
comment
Ваше предложение и предложение @Dukeling сделали свое дело! Спасибо. - person abhishek14d; 22.08.2013

Что не так с использованием регулярных выражений? Вы можете разбить многочлен на мономы, оценить каждый и сложить все результаты.

private static final Pattern monomial = Pattern
        .compile("([+-])?(\\d+)?x(?:\\^(\\d+))?");

public static int eval(String str, String valx) {
    Matcher m = monomial.matcher(str);
    int x = Integer.parseInt(valx);

    int total = 0;
    while (m.find()) {
        String mul = m.group(2);
        int value = (mul == null) ? 1 : Integer.parseInt(m.group(2));

        String pow = m.group(3);
        value *= (pow == null) ? x : (int) Math.pow(x,
                Integer.parseInt(pow));

        if ("-".equals(m.group(1)))
            value = -value;

        total += value;
    }

    return total;
}

System.out.println(eval("-2x^3+10x-4x^2", "3"));
System.out.println(eval("x^3+x^2+x", "6"));
-60
258
person arshajii    schedule 22.08.2013
comment
Определенно самое ясное (и это точно такое же регулярное выражение, которое я бы использовал), но название заставляет меня думать, что это назначение класса, а регулярные выражения запрещены. - person ajb; 23.08.2013

  1. Вам необходимо учитывать последний термин (оператор if сработает только при обнаружении - или +, которых нет в конце).

    Один из простых способов сделать это — заменить:

    for (int i = 0; i < len; i++)
    {
        if (str.charAt(i) == '-' || str.charAt(i) == '+')
    

    с:

    //                 v one more iteration
    for (int i = 0; i <= len; i++)
    {
        if (i == len || str.charAt(i) == '-' || str.charAt(i) == '+')
    //      \------/
    //   extra condition
    

    Вышеупомянутое просто продолжается для еще одной итерации и на этой итерации всегда переходит в оператор if, вызывая обработку последнего термина.

  2. Вы также можете упростить

    if (str.charAt(0) == '-')
    {
      // common code
    }
    else if (str.charAt(0) != '-')
    {
      str = '+' + str;
      // common code
    }
    

    To:

    if (str.charAt(0) != '-')
    {
      str = '+' + str;
    }
    // common code
    
  3. Также есть ошибка с обработкой +. Я получаю NumberFormatException за это. Один из способов справиться с этим — игнорировать + между терминами (и не добавлять + в начало):

    if (i != len && str.charAt(i) == '+')
      str = str.substring(i+1);
    else
      str = str.substring(i);
    
  4. И вы могли бы также сделать свои функции static и вызывать их напрямую, а не объявлять новый экземпляр вашего класса.

Тест.

person Bernhard Barker    schedule 22.08.2013
comment
На самом деле это должно быть (i == len-1) внутри if. Это сработало. Спасибо! - person abhishek14d; 22.08.2013
comment
@abhishek14d i == len вроде работает нормально. Сделал некоторые дополнения к моему ответу. - person Bernhard Barker; 23.08.2013

Простой ответ заключается в том, что когда вы делаете это:

           if(str.charAt(i) == '-' || str.charAt(i) == '+')
            {
                subStr = str.substring(0, i);

эффект заключается в том, что вы устанавливаете subStr в текст непосредственно перед - или + и оцениваете его. Но поскольку в конце строки нет - или +, эта логика никоим образом не будет оценивать последний член многочлена, поскольку она оценивает только подстроки, которые находятся прямо перед - или +.

P.S. Это только одна проблема, которую я заметил. Я не знаю, верна ли остальная логика.

person ajb    schedule 22.08.2013

Когда вы анализируете строку, вы ищете +/- и останавливаетесь только в том случае, если вы их найдете. Это работает для первых двух членов, но когда вы дойдете до «-4x^2», цикл не остановится, потому что нет +/-. Поэтому в дополнение к имеющимся у вас условиям вам нужно добавить код, чтобы при достижении конца строки у вас оставался последний член. Итак, что вы хотите иметь, это

if(str.charAt(0) == '-')
    {
        int len = str.length();
        for (int i = 0; i < len; i++)
        {
            if(str.charAt(i) == '-' || str.charAt(i) == '+')
            {                   
                subStr = str.substring(0, i);
                System.out.println("subStr="+subStr);
                sum += evalSubPoly(subStr, valx);
                str = str.substring(i+1);
                len = str.length();
                i = 0;
            }               
        }
        System.out.println("subStr="+str);
        sum += evalSubPoly(str, valx);
    }


    else if(str.charAt(0) != '-')
    {
        str = '+' + str;
        int len = str.length();
        for (int i = 0; i < len; i++)
        {
            if(str.charAt(i) == '-' || str.charAt(i) == '+')
            {
                subStr = str.substring(0, i);
                System.out.println("subStr="+subStr);
                sum += evalSubPoly(subStr, valx);
                str = str.substring(i+1);
                len = str.length();
                i=0;
            }
        }
        System.out.println("subStr="+str);
        sum += evalSubPoly(str, valx);
    }

Я также выброшу заявление об отказе от ответственности, что может быть больше ошибок, но это основная причина вашей проблемы.

РЕДАКТИРОВАТЬ: добавлено изменение в оператор else if и добавлено изменение, упомянутое в моем комментарии выше.

person Paris Nelson    schedule 22.08.2013

С помощью регулярных выражений вы можете получить более простое решение. И нужна ли вам поддержка простых констант? Попробуйте следующее:

public class EvalPolyX2 {
    public static void main(String args[]) {
        System.out.println("Result: " + eval("x^3+x^2+x", 6));
    }
    public static int eval(String eq, int val) {
        int result = 0;
        String mons[] = eq.split("(?=[+-])(?!\\B)");
        for (String str : mons) {
            str = str.replace("+", "");
            if (str.contains("x")) {
                double a = 1, b = 1;
                String[] comps = str.split("x\\^?");
                if (comps.length > 0) {
                    a = comps[0].isEmpty() ? 1 : Integer.parseInt(comps[0]);
                }
                if (comps.length > 1) {
                    b = Integer.parseInt(comps[1]);
                }
                result += a * Math.pow(val, b);
            } else {
                result += Integer.parseInt(str);
            }
        }
        return result;
    }
}
person Paul Vargas    schedule 22.08.2013