4

If I have a string abcabcabcabc, and an int N 3, I'm trying to return "cccc". I know how to do it with a for loop, but I'm lost on how to do it with recursion.

Would greatly appreciate any help.

Here's what I have so far:

public String everyNth(String s, int n){
    if(s.length() % n == 0){
        return s.charAt(n-1) + "";
    }
    else {
        return everyNth(s.substring(n, s.length()), n);
    }
}

So far it only prints off "c" and not "cccc".

ESM
  • 175
  • 10
  • Start by describing what you are trying to do. ```public String cccc() {return "cccc";}``` You don't need recursion for that. – LowKeyEnergy Nov 19 '19 at 19:54
  • @LowKeyEnergy I'm trying to print off the "nth" character in a string "s", starting from 1 and not 0, which is why n = 3 == c and not a. – ESM Nov 19 '19 at 19:59
  • 1
    If N=3 and s="abcabcabcabc" then the "Nth character in a string s" is just "c" ... so by your own explanation, you want a program that only prints "c". – LowKeyEnergy Nov 19 '19 at 20:07
  • Input `s = "abcabcabcabc"` (length 12) and `n = 3`, so `s.length() % n = 12 % 3 = 0`, which means that `return s.charAt(n-1) + "";` makes the method return `"c"`. – Andreas Nov 19 '19 at 20:10

3 Answers3

4

That's one way

public String everyNth(String s, int n) {
    if (s.length() >= n) {
        return s.charAt(n - 1) + everyNth(s.substring(n), n);
    } else {
        return "";
    }
}

You could formulate a tail recursive version that doesn't need to do anything with returned results. Some languages like Scala can use this for optimization that avoids limited stack depth (and StackOverflow-exceptions), but not java, as for now.

public String everyNthAcc(String s, String acc, int n) {
    if (s.length() >= n) {
        return everyNthAcc(s.substring(n), acc + s.charAt(n - 1), n);
    } else {
        return acc;
    }
}

@Test
public void tryIt() {
    assertEquals("cccc", everyNthAcc("abcabcabcabc","", 3));
}

So as it is for now, the smaller the size of each stack frame, the deeper you can get with the recursion, that should make it further, its a bit weird, though:

public class EveryNth {

    String value = "abcabcabcabc";
    StringBuilder sb = new StringBuilder();
    int nth = 3;

    @Test
    public void tryIt() {
        everyNthAgain(nth);
        assertEquals("cccc", sb.toString());
    }

    public void everyNthAgain(int curr) {
        if (curr <= value.length()) {
            sb.append(value.charAt(curr - 1));
            everyNthAgain(curr + nth);
        }
    }
}
Curiosa Globunznik
  • 3,129
  • 1
  • 16
  • 24
1

This is one way with a little bit of parameter checking. The idea is to send some state along with the recursive call. Each call modifies the state (startingIndex) on the next call. When the state exceeds some condition then the recursion stops. While the recursive calls unwind the resulting string is assembled.

public static void main(String... args) {
    System.out.println(everyNth("abcabcabcabc", 3));
}

public static String everyNth(String s, int n) {
    if (n < 0) {
        return "";
    }
    return everyNth(s, n, n - 1);
}

public static String everyNth(String s, int n, int startingIndex) {
    if (startingIndex < s.length()) {
        return s.charAt(startingIndex) + everyNth(s, n, startingIndex + n);
    }
    return "";
}
fedup
  • 1,209
  • 11
  • 26
1

Here is an approach that does not rely passing an index around, which seems much more for loopy than recursive.

It uses a terminal condition, alters the starting argument with each call, and uses the stack of return values to return the result. The char parameter can get replaced with a hardcoded 'c' if needed.

public String countChar(String s, char c) {
    if (s.length() == 0) return "";
    return (s.charAt(0) == c ? c : "") + countChar(s.substring(1),c);
}
SephB
  • 617
  • 3
  • 6