vendredi 27 décembre 2019

Building a string pattern with two nested for loops makes the code too slow, with two separated, makes it to not pass the tests‽

I am doing the following programming exercise: Complete The Pattern #4. The statement is:

Task:

You have to write a function pattern which creates the following pattern upto n number of rows. If the Argument is 0 or a Negative Integer then it should return "" i.e. empty string.

Examples:

pattern(4):

1234 234 34 4

pattern(6):

123456 23456 3456 456 56 6

Note: There are no blank spaces

Hint: Use \n in string to jump to next line

I have tried the following naive solution:

public class Pattern {

    public static String pattern/*🅿️*/(int n) {
    String result = "";
    for(int i = 1; i <= n; i++){
      for(int j = i; j <= n; j++){
        result += j;
      }      
      result += "\n";
    }
    return result.strip();
    }
}

Which runs out of time (the execution time is longer than 16000 ms) for input of three digits like: 496, 254, 529...

Then, I tried to simplify it, removing the nested loop and just iterating a first time to put all the numbers range, and then iterating a second time to append the rest of the pattern:

public class Pattern {

    public static String pattern/*🅿️*/(int n) {
    System.out.println("n: "+n);
    String result = "";
    for(int i = 1; i <= n; i++){
      result += i;
    }
    System.out.println("result after first loop: "+result);
    for(int i = 1; i < n; i++){
      result += "\n"+result.substring(i,n);
    }
    System.out.println("result after second loop:\n"+result);
    return result.strip();
    }
}

I have been debugging and I have found that this second solution outputs correct only when n is a one digit number. For example when n is 7:

n: 7
result after first loop: 1234567
result after second loop:
1234567
234567
34567
4567
567
67
7

However, when n is a two digits number:

n: 11
result after first loop: 1234567891011
result after second loop:
1234567891011
2345678910
345678910
45678910
5678910
678910
78910
8910
910
10
0

And the output should be:

Expected...
<...567891011
2345678910[11
34567891011
4567891011
567891011
67891011
7891011
891011
91011
1011
11]>

But was...
expected:<...567891011
2345678910[
345678910
45678910
5678910
678910
78910
8910
910
10
0]>

Being the test cases (extracted from the exercise):

import static org.junit.Assert.assertEquals;

import org.junit.Test;

public class PatternTest {
    @Test
    public void pattern() throws Exception {
        assertEquals( Pattern.pattern( 1 ), "1" );
        assertEquals( Pattern.pattern( 2 ), "12\n2" );
        assertEquals( Pattern.pattern( 5 ), "12345\n2345\n345\n45\n5" );
    assertEquals( Pattern.pattern( 7 ), "1234567\n234567\n34567\n4567\n567\n67\n7" );
    assertEquals( Pattern.pattern( 11 ), "1234567891011\n234567891011\n34567891011\n4567891011\n567891011\n67891011\n7891011\n891011\n91011\n1011\n11" );
        assertEquals( Pattern.pattern( 0 ), "" );
        assertEquals( Pattern.pattern( -25 ), "" );
        assertEquals( Pattern.pattern( -59 ), "" );
    }
}

I understand the bug is with result.substring(i,n) because of we are assuming that each number will count as 1 in the oop (will only have one digit), which is incorrect, it could have more digits...

How could we improve this code?‽

I have also read:

Aucun commentaire:

Enregistrer un commentaire