Reverse String II
EasyPrompt
Given a string s and an integer k, reverse the first k characters for every 2k characters counting from the start of the string.
If there are fewer than k characters left, reverse all of them. If there are less than 2k but greater than or equal to k characters, then reverse the first k characters and leave the other as original.
Example 1:
Input: s = "abcdefg", k = 2
Output: "bacdfeg"Example 2:
Input: s = "abcd", k = 2
Output: "bacd"
Constraints:
1 <= s.length <= 104sconsists of only lowercase English letters.1 <= k <= 104
Approaches
2 approaches with complexity analysis and trade-offs.
This approach directly simulates the process described in the problem. We iterate through the string, building a new reversed string piece by piece using a StringBuilder. For every 2k characters, we take the first k, reverse them, and append them to our result, followed by the next k characters which are appended without modification.
Algorithm
- Initialize an empty
StringBuildercalledresult. - Initialize an index
i = 0. - Loop while
iis less than the length of the strings:- Calculate the end index
jof the part to be reversed:j = min(i + k, s.length()). - Extract the substring from
itoj. - Reverse this substring and append it to
result. - Calculate the end index
lof the current2kblock:l = min(i + 2k, s.length()). - If
j < l, append the substring fromjtoltoresult. - Increment
iby2k.
- Calculate the end index
- Return
result.toString().
Walkthrough
We initialize a StringBuilder to construct the final string. The logic iterates through the input string s with a step size of 2k. In each step, we handle a block of up to 2k characters.
- Identify and Reverse: We first determine the segment to be reversed. This segment starts at the current index
iand ends atmin(i + k, s.length()). Thisminfunction correctly handles the case where fewer thankcharacters are left. We extract this substring, reverse it using a temporaryStringBuilder, and append it to our main resultStringBuilder. - Append Unchanged Part: Next, we identify the second part of the block, which should not be reversed. This segment starts where the first one ended and goes up to
min(i + 2k, s.length()). We extract this substring and append it directly to the result. - Iteration: We then advance our main index
iby2kto move to the next block.
After the loop has processed the entire string, we convert the StringBuilder to a string and return it.
class Solution { public String reverseStr(String s, int k) { StringBuilder result = new StringBuilder(); int i = 0; int n = s.length(); while (i < n) { int reverseEnd = Math.min(i + k, n); StringBuilder reversedPart = new StringBuilder(s.substring(i, reverseEnd)); result.append(reversedPart.reverse()); if (reverseEnd < n) { int nonReverseEnd = Math.min(i + 2 * k, n); result.append(s.substring(reverseEnd, nonReverseEnd)); } i += 2 * k; } return result.toString(); }}Complexity
Time
O(N), where N is the length of the string. We iterate through the string once. Operations inside the loop like `substring`, `StringBuilder` creation, and `reverse` take time proportional to `k`. The total time is the sum over all blocks, which is linear in N.
Space
O(N). A `StringBuilder` of size N is used to build the result. Additionally, temporary substrings and `StringBuilder` objects of size up to `k` are created in each iteration, contributing to the overall space usage.
Trade-offs
Pros
Conceptually straightforward, directly translating the problem statement into code.
Relatively easy to implement without complex data structures.
Cons
Less efficient due to the creation of multiple temporary string and
StringBuilderobjects within the loop. This can lead to higher memory overhead and performance degradation from frequent garbage collection.
A more optimized approach involves converting the string to a character array to perform the reversals in-place. This avoids the overhead of creating new string objects repeatedly. We iterate through the array in steps of 2k and reverse the required segments directly within the array using a two-pointer technique.
Algorithm
- Convert the input string
sto a character arraya. - Iterate through the array with an index
startfrom0toa.length - 1, with a step of2 * k. - In each iteration, determine the
leftandrightboundaries of the segment to reverse:left = startright = min(start + k - 1, a.length - 1)
- Call a helper function
reverse(a, left, right). - The
reversefunction swaps elements from the ends towards the center using two pointers until they meet. - After the loop, create a new string from the modified character array
aand return it.
Walkthrough
Since strings are immutable in Java, we first convert the input string s into a character array a. This allows us to modify characters directly.
The main logic iterates through this array with a start index, which is incremented by 2k in each step. This start index marks the beginning of each block to be processed.
For each block, we need to reverse the first k characters. The indices for this reversal are from start to min(start + k - 1, a.length - 1). The min function is key to correctly handling the final part of the string, which might be shorter than k or 2k.
A helper function, reverse(char[] a, int left, int right), performs the in-place reversal. It uses two pointers, left and right, initialized to the start and end of the segment. It swaps the characters at these pointers and moves them towards each other until they cross.
After the loop finishes, the character array a contains the desired arrangement. We then construct a new string from this array and return it.
class Solution { public String reverseStr(String s, int k) { char[] a = s.toCharArray(); for (int start = 0; start < a.length; start += 2 * k) { int i = start; int j = Math.min(start + k - 1, a.length - 1); reverse(a, i, j); } return new String(a); } private void reverse(char[] a, int i, int j) { while (i < j) { char temp = a[i]; a[i] = a[j]; a[j] = temp; i++; j--; } }}Complexity
Time
O(N), where N is the length of the string. We traverse the array once. Each character is visited a constant number of times (once in the main loop, and at most once during a reversal swap). This results in a linear time complexity.
Space
O(N). In Java, this approach requires `O(N)` space to store the character array, as strings are immutable. In languages with mutable strings, this could be an `O(1)` space solution (excluding input storage).
Trade-offs
Pros
More efficient in terms of both time and memory as it avoids creating numerous temporary objects.
Modifies data in-place (on the character array), which is an efficient and common programming pattern.
Cons
Requires an initial
O(N)space overhead to convert the immutable string to a mutable character array in Java.
Solutions
Solution
class Solution {public String reverseStr(String s, int k) { char[] chars = s.toCharArray(); for (int i = 0; i < chars.length; i += (k << 1)) { for (int st = i, ed = Math.min(chars.length - 1, i + k - 1); st < ed; ++st, --ed) { char t = chars[st]; chars[st] = chars[ed]; chars[ed] = t; } } return new String(chars); }}class Solution {public: string reverseStr(string s, int k) { for (int i = 0, n = s.size(); i < n; i += (k << 1)) { reverse(s.begin() + i, s.begin() + min(i + k, n)); } return s; }};''' class range(start, stop, step=1) >>> k = 1 >>> for i in range(0, 9, k): ... print(i) ... 0 1 2 3 4 5 6 7 8 >>> for i in range(0, 9, k << 1): ... print(i) ... 0 2 4 6 8 ''' ''' reversed(t[i : i + k]) VS t[i : i + k][::-1] reversed(t[i : i + k]) returns an iterator that yields elements of the sequence in reverse order more suitable when you don't need a list or are performing operations that can take advantage of an iterator like join() t[i : i + k][::-1] slicing to create a new list that is a reversed version of the slice t[i : i + k] more convenient where you need the reversed sublist to be a list >>> t = [11,22,33,44,55] >>> >>> >>> t[1:3][::-1] [33, 22] >>> >>> reversed(t[1:3]) <list_reverseiterator object at 0x109022950> >>> >>> list(reversed(t[1:3])) [33, 22] ''' class Solution : def reverseStr ( self , s : str , k : int ) -> str : t = list ( s ) for i in range ( 0 , len ( t ), k << 1 ): # protected from out-of-index error t [ i : i + k ] = reversed ( t [ i : i + k ]) return '' . join ( t ) ############ class Solution ( object ): def reverseStr ( self , s , k ): """ :type s: str :type k: int :rtype: str """ cnt = 0 isFirst = True a = "" b = "" ans = [] for c in s : if isFirst : a = c + a else : b += c cnt += 1 if cnt == k : if isFirst : ans . append ( a ) a = "" else : ans . append ( b ) b = "" isFirst = not isFirst cnt = 0 return "" . join ( ans ) + a + bVideo 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.