简体   繁体   中英

How to solve the “repeatSeparator” problem without a loop in Java?

There is a problem on CodingBat called repeatSeparator .

Given two strings, word and a separator sep, return a big string made of count occurrences of the word, separated by the separator string.

repeatSeparator("Word", "X", 3) → "WordXWordXWord"
repeatSeparator("This", "And", 2) → "ThisAndThis"
repeatSeparator("This", "And", 1) → "This"

I know how to solve it but my solution and most solutions I find on the internet uses a loop. Is there a way to solve this problem without a loop?

A pseudocode of my need return (word+rep)*count; which won't work but is there a way to achieve similiar result?

I'd highly value any reply.

One liner using Java 11:

String repeatSeparator(String word, String sep, int count) {
    return (word + sep).repeat(count-1) + word;
}

One liner using Java 8:

String repeatSeparator(String word, String sep, int count) {
    return String.join(sep, Collections.nCopies(count, word));
}

If you absolutely want to hide the loops in the implementation, you could do something like this:

public String repeatSeparator(String word, String separator, int count) {
    return IntStream.range(0, count)
        .mapToObj(i -> word)
        .collect(Collectors.joining(separator));
}

The code above generates the numbers between 0 and count-1, replaces each number with the given word and finally concatenates them with the given separator.

Note that this still uses loops, they're just hidden inside the streams. Worse still, this solution is almost certainly way less efficient than a naive StringBuilder+for solution.

Edit: A (potentially) simpler version of the same idea:

public String repeatSeparator(String word, String separator, int count) {
    return Stream.generate(() -> word)
        .limit(count)
        .collect(Collectors.joining(separator));
}

Create an infinite stream of the word, limit it to the given count, then concatenate them with the separator.

You can do it by the combined use of the following methods/functions:

  1. Arrays::fill
  2. String::join

Demo:

import java.util.Arrays;

public class Main {
    public static void main(String[] args) {
        // Tests
        System.out.println(repeatSeparator("Word", "X", 3));
        System.out.println(repeatSeparator("This", "And", 2));
        System.out.println(repeatSeparator("This", "And", 1));
    }

    static String repeatSeparator(String word, String separator, int n) {
        String[] arr = new String[n];
        Arrays.fill(arr, word);
        return String.join(separator, arr);
    }
}

Output:

WordXWordXWord
ThisAndThis
This

If you are allowed to use Java11, you can use String:repeat as follows:

static String repeatSeparator(String word, String separator, int n) {
    return (word + separator).repeat(n - 1) + word;
}

As stated in a comment and in @ackdari's answer, you can use a recursion. I suggest the divide and conquer method:

static String repeatSeparator(String word, String separator, int n) {
    if (n == 1) {
        return word;
    } else {
        String s = repeatSeparator(word, separator, n / 2); // half the expected string
        String ret = s + separator + s; // concatenate both halves
        if (n % 2 == 1) {
            ret += separator + word; // if there's an odd number of words, add the last word.
        }
        return ret;
    }
}

Although the time complexity seems to be O(lg n) , that's not the case unless the operations on strings (copy, concatenate) are atomic. And this code will probably be slower than the code of the other examples.

If you just want to avoid using a loop you can simply do an recursion. Since this is somekind of exceris I will just brifly outline a solution.

To find a recusive solution to a problem you first have to find the base case(s). The problem of joining a string with a seperator has two base cases.

  • repeat the word zero times
  • repeat the word one time

Now, to create a recursive solution you have to somehow reduce the case repeat the word n times to repeat the word m times where m < n .

One solution with Collections.nCopies

String repeatSeparator(String word, String separator, int count) {
    return Collections.nCopies(count, word).stream()
            .collect(Collectors.joining(separator));;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM