Talentd
FleetCode
Make and follow sheets.Sign in

Split Strings by Separator solution and explanation

EasyArrayString6 min read76.1% acceptanceUpdated 9 Apr 2026
Leetcode | 2788. Split Strings by Separator | Easy | Java SolutionDeveloper Docs · 7:04 · 937 viewsWatch on YouTube
9 more videos on this problem
  1. Leetcode | 2788. Split Strings by Separator | Easy | Java SolutionDeveloper Docs · 7:04 · 937 views
  2. 6921. Split Strings by Separator | Leetcode Weekly Contest 355 | Solution Code In Comment.Optimization · 0:19 · 700 views
  3. Leetcode Weekly contest 355 - Easy - Split Strings by SeparatorPrakhar Agrawal · 4:29 · 638 views
  4. Split Strings by Separator | Leetcode 2788 | Contest 355Tech Courses · 3:55 · 620 views
  5. 2788. Split Strings by Separator (Leetcode Easy)Programming Live with Larry · 2:23 · 459 views
  6. LeetCode 2788 | Split Strings by Separator | Solution explained in JavaMichael Herman · 8:28 · 330 views
  7. Crack String Manipulation in Python with this Easy LeetCode 2788. Split Strings by SeparatorvanAmsen · 4:56 · 297 views
  8. 2788. Split Strings by Separator || Weekly Contest 355 || Leetcode || HindiAshish Kumar · 2:47 · 252 views
  9. Leetcode 6921. Split Strings by Separator || Weekly Contest 355ExpertFunda · 6:25 · 165 views
  10. Split Strings by Separator #leetcode #leetcodequestionandanswers #arrays #googleinterview #stringsCodeVia · 2:40 · 43 views

The problem

Given an array of strings words and a character separator, split each string in words by separator.

Return an array of strings containing the new strings formed after the splits, excluding empty strings.

Notes

  • separator is used to determine where the split should occur, but it is not included as part of the resulting strings.
  • A split may result in more than two strings.
  • The resulting strings must maintain the same order as they were initially given.

Example 1:

Input: words = ["one.two.three","four.five","six"], separator = "."
Output: ["one","two","three","four","five","six"]
Explanation: In this example we split as follows:

"one.two.three" splits into "one", "two", "three"
"four.five" splits into "four", "five"
"six" splits into "six" 

Hence, the resulting array is ["one","two","three","four","five","six"].

Example 2:

Input: words = ["$easy$","$problem$"], separator = "$"
Output: ["easy","problem"]
Explanation: In this example we split as follows: 

"$easy$" splits into "easy" (excluding empty strings)
"$problem$" splits into "problem" (excluding empty strings)

Hence, the resulting array is ["easy","problem"].

Example 3:

Input: words = ["|||"], separator = "|"
Output: []
Explanation: In this example the resulting split of "|||" will contain only empty strings, so we return an empty array []. 

Constraints:

  • 1 <= words.length <= 100
  • 1 <= words[i].length <= 20
  • characters in words[i] are either lowercase English letters or characters from the string ".,|$#@" (excluding the quotes)
  • separator is a character from the string ".,|$#@" (excluding the quotes)

Approach overview

Problem Overview: You receive an array of strings and a separator character. For each string, split it by the separator and collect all non-empty substrings into a single result list. Empty tokens created by consecutive separators must be ignored.

Approach 1: String Split and Filter (O(n) time, O(n) space)

The simplest solution uses the language's built-in split() operation. Iterate through each string in the input array, call split(separator), and append every non-empty token to the result list. The key insight: most languages already implement efficient substring scanning, so you avoid writing the parsing logic yourself. After splitting, filter tokens where token.length == 0 to remove empty segments created by repeated separators like "a,,b". Since every character across all strings is processed once, the total time complexity is O(n), where n is the total number of characters across the array. Space complexity is O(n) for the output list.

This approach is concise and highly readable. It works well in interviews when the language's standard library is allowed. It also aligns naturally with problems involving string manipulation and array traversal.

Approach 2: Manual String Traversal (O(n) time, O(k) space)

Instead of calling split(), parse each string character by character. Maintain a temporary buffer (or start index) to build the current substring. When the separator is encountered, push the accumulated substring to the result only if it is non-empty, then reset the buffer. Continue scanning until the end of the string and append the final segment if it exists. This method gives full control over parsing and avoids allocating intermediate arrays that split() might create.

Every character is visited exactly once, so the time complexity remains O(n). Space complexity is O(k) for the current substring buffer plus the output list. This pattern appears frequently in problems involving manual parsing, tokenization, or streaming input processing.

Recommended for interviews: The built-in split solution is usually the expected answer because it demonstrates clean use of standard libraries and keeps the implementation short. Interviewers may ask for the manual traversal approach as a follow-up to confirm you understand how string parsing works internally. Showing both approaches demonstrates strong fundamentals in string processing and efficient iteration over collections.

Approach 1: Approach 1: String Split and Filter

This approach involves using the built-in string split functionality that most high-level languages offer. The idea is to iterate over each string in the words array, split them using the given separator, and filter out any empty strings from the results of the split.

def split_strings(words, separator):
    result = []
    for word in words:
        parts = word.split(separator)
        result.extend([part for part in parts if part])
    return result

words = ["one.two.three", "four.five", "six"]
separator = '.'
result = split_strings(words, separator)
for word in result:
    print(word)
import java.util.ArrayList;
import java.util.List;

public class StringSplit {
    public static List<String> splitStrings(String[] words, char separator) {
        List<String> result = new ArrayList<>();
        for (String word : words) {
            String[] parts = word.split(Character.toString(separator));
            for (String part : parts) {
                if (!part.isEmpty()) {
                    result.add(part);
                }
            }
        }
        return result;
    }

    public static void main(String[] args) {
        String[] words = {"one.two.three", "four.five", "six"};
        char separator = '.';
        List<String> result = splitStrings(words, separator);
        for (String word : result) {
            System.out.println(word);
        }
    }
}
#include <iostream>
#include <vector>
#include <sstream>

std::vector<std::string> split_string(const std::string& str, char separator) {
    std::vector<std::string> result;
    std::stringstream ss(str);
    std::string segment;
    while (std::getline(ss, segment, separator)) {
        if (!segment.empty()) {
            result.push_back(segment);
        }
    }
    return result;
}

std::vector<std::string> split_strings(const std::vector<std::string>& words, char separator) {
    std::vector<std::string> result;
    for (const auto& word : words) {
        auto segments = split_string(word, separator);
        result.insert(result.end(), segments.begin(), segments.end());
    }
    return result;
}

int main() {
    std::vector<std::string> words = {"one.two.three", "four.five", "six"};
    char separator = '.';
    auto result = split_strings(words, separator);
    for (const auto& word : result) {
        std::cout << word << "\n";
    }
    return 0;
}
function splitStrings(words, separator) {
    let result = [];
    for (let word of words) {
        let parts = word.split(separator).filter(part => part);
        result.push(...parts);
    }
    return result;
}

let words = ["one.two.three", "four.five", "six"];
let separator = '.';
let result = splitStrings(words, separator);
console.log(result);
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

char** split_and_filter(char* word, char separator, int* count) {
    char** result = malloc(sizeof(char*) * 20); // assuming max 20 parts
    char* token;
    int index = 0;
    token = strtok(word, &separator);
    while (token != NULL) {
        if (strlen(token) > 0) {
            result[index] = malloc(strlen(token) + 1);
            strcpy(result[index], token);
            index++;
        }
        token = strtok(NULL, &separator);
    }
    *count = index;
    return result;
}

char** split_strings(char** words, int wordsSize, char separator, int* returnSize) {
    char** result = malloc(sizeof(char*) * 100); // assuming max 100 results
    int index = 0;
    for (int i = 0; i < wordsSize; i++) {
        int count;
        char* wordCopy = strdup(words[i]);
        char** parts = split_and_filter(wordCopy, separator, &count);
        for (int j = 0; j < count; j++) {
            result[index++] = parts[j];
        }
        free(wordCopy);
        free(parts);
    }
    *returnSize = index;
    return result;
}

int main() {
    char* words[] = {"one.two.three", "four.five", "six"};
    char separator = '.';
    int returnSize;
    char** result = split_strings(words, 3, separator, &returnSize);
    for (int i = 0; i < returnSize; i++) {
        printf("%s\n", result[i]);
        free(result[i]);
    }
    free(result);
    return 0;
}
using System;
using System.Collections.Generic;

public class StringSplitter {
    public static List<string> SplitStrings(string[] words, char separator) {
        List<string> result = new List<string>();
        foreach (var word in words) {
            var parts = word.Split(new char[] { separator }, StringSplitOptions.RemoveEmptyEntries);
            result.AddRange(parts);
        }
        return result;
    }

    public static void Main() {
        string[] words = { "one.two.three", "four.five", "six" };
        char separator = '.';
        List<string> result = SplitStrings(words, separator);
        foreach (var word in result) {
            Console.WriteLine(word);
        }
    }
}

In Python, the solution uses the str.split() method to divide the string by the separator, and a list comprehension is employed to filter out empty strings before compiling the results.

Complexity

Time Complexity: O(n * m) with n as the array size and m as the average size of strings.
Space Complexity: O(n * m) because of storage for resulting strings.

Try this approach in the editor

Approach 2: Approach 2: Manual String Traversal

Instead of utilizing built-in split functions, this approach manually traverses each string character by character, identifying substrings between occurrences of the separator and directly constructing the result list. It can offer additional flexibility or optimizations in environments where built-in functions are inefficient.

def manual_split_string(word, separator):
    result = []
    buffer = []
    for char in word:
        if char == separator:
            if buffer:
                result.append(''.join(buffer))
                buffer = []
        else:
            buffer.append(char)
    if buffer:
        result.append(''.join(buffer))
    return result

def manual_split_strings(words, separator):
    result = []
    for word in words:
        result.extend(manual_split_string(word, separator))
    return result

words = ['one.two.three', 'four.five', 'six']
separator = '.'
result = manual_split_strings(words, separator)
for part in result:
    print(part)
import java.util.ArrayList;
import java.util.List;

public class StringTraversal {
    public static List<String> manualSplitString(String word, char separator) {
        List<String> result = new ArrayList<>();
        StringBuilder buffer = new StringBuilder();
        for (char ch : word.toCharArray()) {
            if (ch == separator) {
                if (buffer.length() > 0) {
                    result.add(buffer.toString());
                    buffer.setLength(0);
                }
            } else {
                buffer.append(ch);
            }
        }
        if (buffer.length() > 0) {
            result.add(buffer.toString());
        }
        return result;
    }

    public static List<String> manualSplitStrings(String[] words, char separator) {
        List<String> result = new ArrayList<>();
        for (String word : words) {
            result.addAll(manualSplitString(word, separator));
        }
        return result;
    }

    public static void main(String[] args) {
        String[] words = {"one.two.three", "four.five", "six"};
        char separator = '.';
        List<String> result = manualSplitStrings(words, separator);
        for (String part : result) {
            System.out.println(part);
        }
    }
}
#include <iostream>
#include <vector>
using namespace std;

vector<string> manual_split_string(const string& str, char separator) {
    vector<string> result;
    string buffer = "";
    for (char ch : str) {
        if (ch == separator) {
            if (!buffer.empty()) {
                result.push_back(buffer);
                buffer = "";
            }
        } else {
            buffer += ch;
        }
    }
    if (!buffer.empty()) {
        result.push_back(buffer);
    }
    return result;
}

vector<string> manual_split_strings(const vector<string>& words, char separator) {
    vector<string> result;
    for (const auto& word : words) {
        auto splits = manual_split_string(word, separator);
        result.insert(result.end(), splits.begin(), splits.end());
    }
    return result;
}

int main() {
    vector<string> words = {"one.two.three", "four.five", "six"};
    char separator = '.';
    vector<string> result = manual_split_strings(words, separator);
    for (const string& part : result) {
        cout << part << endl;
    }
    return 0;
}
function manualSplitString(word, separator) {
    let result = [];
    let buffer = '';
    for (let char of word) {
        if (char === separator) {
            if (buffer.length > 0) {
                result.push(buffer);
                buffer = '';
            }
        } else {
            buffer += char;
        }
    }
    if (buffer.length > 0) {
        result.push(buffer);
    }
    return result;
}

function manualSplitStrings(words, separator) {
    let result = [];
    for (let word of words) {
        result = result.concat(manualSplitString(word, separator));
    }
    return result;
}

let words = ['one.two.three', 'four.five', 'six'];
let separator = '.';
let result = manualSplitStrings(words, separator);
console.log(result);
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char** manual_split_and_filter(const char* word, char separator, int* count) {
    int length = strlen(word);
    char** result = malloc(20 * sizeof(char*)); // assuming a max of 20 segments
    char buffer[21]; // enough to hold a word segment
    int idx = 0, res_idx = 0;
    for (int i = 0; i < length; i++) {
        if (word[i] == separator) {
            if (idx > 0) {
                buffer[idx] = '\0';
                result[res_idx] = strdup(buffer);
                res_idx++;
                idx = 0;
            }
        } else {
            buffer[idx++] = word[i];
        }
    }
    if (idx > 0) {
        buffer[idx] = '\0';
        result[res_idx++] = strdup(buffer);
    }
    *count = res_idx;
    return result;
}

char** manual_split_strings(char** words, int wordsSize, char separator, int* returnSize) {
    char** result = malloc(100 * sizeof(char*));
    int total_cnt = 0;
    for (int i = 0; i < wordsSize; i++) {
        int count;
        char** parts = manual_split_and_filter(words[i], separator, &count);
        for (int j = 0; j < count; j++) {
            result[total_cnt++] = parts[j];
        }
        free(parts);
    }
    *returnSize = total_cnt;
    return result;
}

int main() {
    char* words[] = {"one.two.three", "four.five", "six"};
    char separator = '.';
    int returnSize;
    char** result = manual_split_strings(words, 3, separator, &returnSize);
    for (int i = 0; i < returnSize; i++) {
        printf("%s\n", result[i]);
        free(result[i]);
    }
    free(result);
    return 0;
}
using System;
using System.Collections.Generic;

public class ManualTraversal {
    public static List<string> ManualSplitString(string word, char separator) {
        List<string> result = new List<string>();
        string buffer = "";
        foreach (char ch in word) {
            if (ch == separator) {
                if (buffer.Length > 0) {
                    result.Add(buffer);
                    buffer = "";
                }
            } else {
                buffer += ch;
            }
        }
        if (buffer.Length > 0) {
            result.Add(buffer);
        }
        return result;
    }

    public static List<string> ManualSplitStrings(string[] words, char separator) {
        List<string> result = new List<string>();
        foreach (string word in words) {
            result.AddRange(ManualSplitString(word, separator));
        }
        return result;
    }

    public static void Main() {
        string[] words = { "one.two.three", "four.five", "six" };
        char separator = '.';
        List<string> result = ManualSplitStrings(words, separator);
        foreach (var str in result) {
            Console.WriteLine(str);
        }
    }
}

This Python code executes a manual traversal over each string, capturing groups of characters into a buffer until a split point (separator) is encountered. Non-empty buffers are added to the result list.

Complexity

Time Complexity: O(n * m), handling each character in the input.
Space Complexity: O(n * m) to save output non-empty segments.

Try this approach in the editor

Approach 3: Simulation

We traverse the string array words. For each string w, we use separator as the delimiter to split it. If the split string is not empty, we add it to the answer array.

The time complexity is O(n times m), and the space complexity is O(m), where n is the length of the string array words, and m is the maximum length of the strings in the array words.

function splitWordsBySeparator(words: string[], separator: string): string[] {
    return words.flatMap(w => w.split(separator).filter(s => s.length > 0));
}
func splitWordsBySeparator(words []string, separator byte) (ans []string) {
	for _, w := range words {
		for _, s := range strings.Split(w, string(separator)) {
			if s != "" {
				ans = append(ans, s)
			}
		}
	}
	return
}
Try this approach in the editor

Complexity comparison

ApproachComplexity
Approach 1: String Split and Filter

Time Complexity: O(n * m) with n as the array size and m as the average size of strings.
Space Complexity: O(n * m) because of storage for resulting strings.

Approach 2: Manual String Traversal

Time Complexity: O(n * m), handling each character in the input.
Space Complexity: O(n * m) to save output non-empty segments.

Simulation–

Complexity analysis

ApproachTimeSpaceWhen to Use
String Split and FilterO(n)O(n)Best general solution when standard library functions like split() are allowed
Manual String TraversalO(n)O(k)Useful when implementing custom parsers or avoiding intermediate arrays

Frequently asked questions

Is Split Strings by Separator easy or hard?

Split Strings by Separator is classified as an Easy problem. The main requirement is understanding basic string operations and filtering empty substrings after splitting.

Split Strings by Separator Python/Java solution

In Python, iterate through the words list, call word.split(separator), and append non-empty strings to the result list. In Java, use String.split with a loop to filter empty tokens. Both implementations run in O(n) time.

How to solve Split Strings by Separator in O(n)?

Iterate through each string and either call split(separator) or manually scan characters while building substrings. Each character is processed exactly once, and non-empty segments are appended to the result list. This guarantees linear time complexity O(n).

What is the best approach for Split Strings by Separator?

The most practical approach uses the built-in split() function for each string and filters out empty tokens. This processes all characters once and keeps the implementation concise. The overall time complexity is O(n), where n is the total number of characters across all strings.

Is Split Strings by Separator asked at Google/Amazon/Meta?

String parsing and tokenization problems frequently appear in interviews at companies like Amazon, Google, and Meta. While this exact problem may vary, the pattern of splitting strings and filtering tokens is a common interview exercise.

What data structure is used in Split Strings by Separator?

The main structure is a dynamic list or array that stores the resulting substrings. During manual traversal, a temporary string buffer or index pointer is used to build segments before adding them to the result.

What is the time complexity of Split Strings by Separator?

The optimal solution runs in O(n) time because each character in the input array is examined once during splitting or traversal. Space complexity is O(n) for storing the resulting substrings.

Comments

Now write it yourselfClose this page and solve Split Strings by Separator in the editor, without looking.
Practise Split Strings by Separator