Search code examples
javarecursionintegerstackstack-overflow

What is causing StackoverFlowError in my code?


I need to write two recusion methods. One of them checks candidate values which need to be enumerated from its most-significant to least-significant digits. For example if numbers are in three-digits it need to be 124 126 128 134 136 138 146 148 156 and so on up to 999 (also even).

I wrote two of them there is no problem in one, two and three digits however, after four digits something cause java.lang.StackOverflowError How can I solve this problem ?

  public boolean checkRec(int num)
   {
      String numLong = String.valueOf(num);
      if((Integer.valueOf(numLong.substring(numLong.length()-1)) % 2) != 0)
         return false;      
      if(numLong.length() == 1)
         return true;
      else
      {
         if(Integer.valueOf(numLong.substring(0,1)) >= Integer.valueOf(numLong.substring(1,2)))
         {
           // System.out.println("asd");
          return false;
         }
         numLong = numLong.substring(1);
         num = Integer.valueOf(numLong);
         return checkRec(num);
      }
   }
public String orderAndPrint(int num, int decimal)
       {
          if(num >= Math.pow(10, decimal+1))
            return "End";
          else
          {
             if(checkRec(num))
             {
                return "" + num + " " + orderAndPrint((num + 2), decimal);
             }
             return orderAndPrint((num + 2), decimal);
          }

Solution

  • You do like recursions :-). How about this function pair:

    public boolean check(int num)
    {
        // This is actually unnecessary as check is called only for even numbers
        if ((num % 2) != 0)
            return false;
        int prev_digit = 10;
        while (num > 0) {
            int last_digit = num % 10;
            if (last_digit >= prev_digit)
                return false;
            prev_digit = last_digit;
            num = num / 10;
        }
        return true;
    }
    
    public String orderAndPrint(int decimal)
    {
        String outstr = ""
        int last_num = Math.pow(10, decimal);
        int num = 2;
        for ( ; num < last_num; num += 2) {
            if (check(num))
                outstr = outstr + num + " ";
        }
        return outstr + "End";
    }
    

    But, this piece of code just replicates what you have done more efficiently, without recursion.

    However, you can code to just generate the appropriate numbers, and there you actually need recursion. Note that the largest possible such number is 12345678, so the max number of digits is 8 and all such numbers fit into an int. Also, none of the digits will be greater than 8, and only the last may be 8.

    public String addnumbers (int n, int digitsleft, String outstr)
    {
        int d;
        int last_digit = n % 10;
        if (digitsleft == 1) {
            d = (last_digit+1) % 2 == 0 ? last_digit+1 : last_digit+2;
            for ( ; d <= 8; d += 2) {
                outstr = outstr + (10*n+d) + " ";
            }
        }
        else {
            for (d=last_digit+1; d < 8; ++d) {
                outstr = addnumbers(10*n+d, digitsleft-1, outstr);
            }
        }
        return outstr;
    }
    public String orderAndPrint(int decimal)
    {
        // Assume decimal is at least 1
        String outstr = "2 4 6 8 "
        int d;
    
        decimal = Math.min(8, decimal);
        for (d = 1; d < 8; ++d) {
            outstr = addnumbers(d, decimal-1, outstr);
        }
        return outstr + "End";
    }
    

    Note that this could be further sped up by using a better upper bound on d in the loops. For example, if after the current one there are still 2 more digits, then d can't be larger than 6. But that would have just obfuscated the code.