Divide a String Into Groups of Size k
EasyPrompt
A string s can be partitioned into groups of size k using the following procedure:
- The first group consists of the first
kcharacters of the string, the second group consists of the nextkcharacters of the string, and so on. Each element can be a part of exactly one group. - For the last group, if the string does not have
kcharacters remaining, a characterfillis used to complete the group.
Note that the partition is done so that after removing the fill character from the last group (if it exists) and concatenating all the groups in order, the resultant string should be s.
Given the string s, the size of each group k and the character fill, return a string array denoting the composition of every group s has been divided into, using the above procedure.
Example 1:
Input: s = "abcdefghi", k = 3, fill = "x"
Output: ["abc","def","ghi"]
Explanation:
The first 3 characters "abc" form the first group.
The next 3 characters "def" form the second group.
The last 3 characters "ghi" form the third group.
Since all groups can be completely filled by characters from the string, we do not need to use fill.
Thus, the groups formed are "abc", "def", and "ghi".Example 2:
Input: s = "abcdefghij", k = 3, fill = "x"
Output: ["abc","def","ghi","jxx"]
Explanation:
Similar to the previous example, we are forming the first three groups "abc", "def", and "ghi".
For the last group, we can only use the character 'j' from the string. To complete this group, we add 'x' twice.
Thus, the 4 groups formed are "abc", "def", "ghi", and "jxx".
Constraints:
1 <= s.length <= 100sconsists of lowercase English letters only.1 <= k <= 100fillis a lowercase English letter.
Approaches
2 approaches with complexity analysis and trade-offs.
This approach iterates through the string s with a step size of k. In each step, it extracts a substring of length k. If the last substring is shorter than k, it's padded with the fill character.
Algorithm
- Calculate the total number of groups required:
(s.length() + k - 1) / k. - Create a string array
resultof this size. - Loop through the string
swith an indexistarting at 0 and incrementing byk. - In each iteration, get the substring from
itomin(i + k, s.length()). - If the substring length is less than
k, pad it with thefillcharacter using aStringBuilder. - Add the (potentially padded) group to the
resultarray. - Return the
resultarray.
Walkthrough
This method directly implements the grouping logic by stepping through the string in chunks of size k.
-
Algorithm:
- First, determine the number of groups that will be created. This is the length of the string
sdivided byk, rounded up. In integer arithmetic, this can be calculated as(s.length() + k - 1) / k. - Create a string array
resultof this calculated size to store the groups. - Iterate through the string
susing an indexithat starts at 0 and increments bykin each step (i += k). - In each iteration, extract the substring for the current group. The substring starts at index
iand ends atmin(i + k, s.length()). This handles the case where the last group might be smaller thank. - If the extracted substring's length is less than
k, it means we are at the last group and it needs padding. AStringBuilderis used to append thefillcharacter the required number of times. - If the substring's length is exactly
k, it can be used as is. - Store the resulting group string (padded or not) in the
resultarray. - After the loop completes, return the
resultarray.
- First, determine the number of groups that will be created. This is the length of the string
-
Code Snippet:
class Solution { public String[] divideString(String s, int k, char fill) { int n = s.length(); int numGroups = (n + k - 1) / k; String[] result = new String[numGroups]; int resultIndex = 0; for (int i = 0; i < n; i += k) { int end = Math.min(i + k, n); String group = s.substring(i, end); if (group.length() < k) { StringBuilder sb = new StringBuilder(group); int remaining = k - group.length(); for (int j = 0; j < remaining; j++) { sb.append(fill); } result[resultIndex++] = sb.toString(); } else { result[resultIndex++] = group; } } return result; }}Complexity
Time
O(N), where N is the length of the string `s`. The main loop runs `N/k` times. Inside the loop, `s.substring()` takes O(k) time to copy characters, and padding also takes at most O(k) time. The total time complexity is `(N/k) * O(k) = O(N)`.
Space
O(N), where N is the length of the string `s`. This space is primarily for the output array, which stores strings whose total length is at least N.
Trade-offs
Pros
The code is highly readable and directly translates the problem statement into logic.
It's a very straightforward and easy-to-understand implementation.
Cons
Creating a new substring object in each iteration can introduce a slight performance overhead due to object creation and memory copying, especially compared to a single-pass approach.
This approach iterates through the input string character by character only once, building each group in a StringBuilder. When a group is complete, it's added to the result list, and the StringBuilder is reset for the next group. This is generally more efficient as it avoids creating multiple intermediate substring objects.
Algorithm
- Initialize an
ArrayList<String>and an emptyStringBuildercurrentGroup. - Iterate through each character of the input string
s. - Append the character to
currentGroup. - If
currentGroup.length()equalsk, add its string representation to the list and resetcurrentGroup. - After the loop, if
currentGroupis not empty, pad it with thefillcharacter until its length isk. - Add the final group to the list.
- Convert the list to a string array and return it.
Walkthrough
This optimized approach avoids repeated substring creation by building the groups directly while iterating through the input string once.
-
Algorithm:
- Initialize an
ArrayList<String>to dynamically store the resulting groups. - Initialize an empty
StringBuildernamedcurrentGroup. - Iterate through the input string
sfrom the first character to the last. - For each character, append it to the
currentGroup. - After appending, check if the length of
currentGrouphas reachedk. - If it has, a complete group has been formed. Convert
currentGroupto a string, add it to the result list, and resetcurrentGroup(e.g., by callingsetLength(0)). - After the loop finishes, check if
currentGroupcontains any characters. This happens if the total length ofsis not a multiple ofk. - If
currentGroupis not empty, it represents the last, incomplete group. Pad it by appending thefillcharacter until its length becomesk. - Add this final, padded group to the result list.
- Finally, convert the list of strings into a string array and return it.
- Initialize an
-
Code Snippet:
import java.util.ArrayList;import java.util.List; class Solution { public String[] divideString(String s, int k, char fill) { List<String> resultList = new ArrayList<>(); StringBuilder currentGroup = new StringBuilder(); for (char c : s.toCharArray()) { currentGroup.append(c); if (currentGroup.length() == k) { resultList.add(currentGroup.toString()); currentGroup.setLength(0); // More efficient than new StringBuilder() } } // Handle the last group if it's not full if (currentGroup.length() > 0) { while (currentGroup.length() < k) { currentGroup.append(fill); } resultList.add(currentGroup.toString()); } return resultList.toArray(new String[0]); }}Complexity
Time
O(N), where N is the length of the string `s`. The string is traversed only once. Appending to a `StringBuilder` is an amortized O(1) operation. The total time is dominated by the single pass through the string.
Space
O(N), where N is the length of the string `s`. O(N) space is required for the output list/array. The auxiliary space used by the `StringBuilder` is O(k).
Trade-offs
Pros
More memory and time-efficient as it avoids creating new substring objects for each group.
Processes the string in a single, continuous pass.
Cons
The logic can be slightly more complex to follow than the direct
substringapproach, as it involves managing the state of theStringBuilderand handling the final partial group as a separate case after the loop.
Solutions
Solution
class Solution {public String[] divideString(String s, int k, char fill) { int n = s.length(); String[] ans = new String[(n + k - 1) / k]; if (n % k != 0) { s += String.valueOf(fill).repeat(k - n % k); } for (int i = 0; i < ans.length; ++i) { ans[i] = s.substring(i * k, (i + 1) * k); } return ans; }}class Solution {public: vector<string> divideString(string s, int k, char fill) { int n = s.size(); if (n % k) for (int i = 0; i < k - n % k; ++i) s.push_back(fill); vector<string> ans; for (int i = 0; i < s.size() / k; ++i) ans.push_back(s.substr(i * k, k)); return ans; }};class Solution: def divideString(self, s: str, k: int, fill: str) -> List[str]: return [ s[i: i + k]. ljust(k, fill) for i in range(0, len(s), k)]Video walkthrough
Newsletter
One sharp idea, every week
System design and interview prep — short enough to finish.
No spam. Unsubscribe anytime.
Practice
Same difficulty — related problems to reinforce the pattern.