Given a string s and a number of rows numRows, arrange the string in an L-shaped pattern from top to bottom, left to right. Then, read the characters row by row from left to right to produce a new string. Implement this transformation with the function signature:
transform(s: string, numRows: number) => string
For example, with input string "ABCDEFGHIJKLMNO" and 3 rows, the arrangement is as follows (using '-' as placeholders):
A--F--K
B--G--L
CDEHIJMNO
Output: "AFKBGLCDEHIJMNO"
With 4 rows:
A---H---O
B---I---
C---J---
DEFGKLMN
Output: "AHOBICJDFEGKLMN"
With 5 rows:
A----J
B----K
C----L
D----M
EFGHINO
Output: "AJBKCLDMEFGHINO"
Solution Approaches
Method 1: 2D Matrix Simulation
/**
* Method 1: 2D Matrix Simulation
* @param {string} inputStr
* @param {number} totalRows
* @return {string}
*/
const transformWithMatrix = (inputStr, totalRows) => {
const strLength = inputStr.length;
const rows = totalRows;
if (rows === 1 || rows >= strLength) {
return inputStr;
}
const period = rows * 2 - 1;
const cols = Math.ceil(strLength / period) * rows;
const grid = new Array(rows).fill(0).map(() => new Array(cols).fill(0));
let currentRow = 0, currentCol = 0;
for (let i = 0; i < strLength; ++i) {
grid[currentRow][currentCol] = inputStr[i];
if (i % period < rows - 1) {
currentRow++;
} else {
currentCol++;
}
if ((i + 1) < strLength && (i + 1) % period === 0) {
currentRow = 0;
}
}
const result = [];
for (const row of grid) {
for (const char of row) {
if (char !== 0) {
result.push(char);
}
}
}
return result.join('');
};
Method 2: Optimized Matrix Representation
/**
* Method 2: Optimized Matrix Representation
* @param {string} inputStr
* @param {number} totalRows
* @return {string}
*/
const transformOptimized = (inputStr, totalRows) => {
const strLength = inputStr.length;
const rows = totalRows;
if (rows === 1 || rows >= strLength) {
return inputStr;
}
const rowBuffers = new Array(rows).fill(0).map(() => []);
const period = rows * 2 - 1;
let currentRow = 0;
for (let i = 0; i < strLength; ++i) {
rowBuffers[currentRow].push(inputStr[i]);
if (i % period < rows - 1) {
currentRow++;
}
if ((i + 1) < strLength && (i + 1) % period === 0) {
currentRow = 0;
}
}
return rowBuffers.flat().join('');
};
Method 3: Direct Construction
/**
* Method 3: Direct Construction
* @param {string} inputStr
* @param {number} totalRows
* @return {string}
*/
const transformDirect = (inputStr, totalRows) => {
const strLength = inputStr.length;
const rows = totalRows;
if (rows === 1 || rows >= strLength) {
return inputStr;
}
const period = rows * 2 - 1;
const result = [];
for (let rowIndex = 0; rowIndex < rows; rowIndex++) {
for (let baseIndex = 0; baseIndex < strLength - rowIndex; baseIndex += period) {
const charIndex = baseIndex + rowIndex;
if (charIndex < strLength) {
result.push(inputStr[charIndex]);
}
if (rowIndex === rows - 1) {
for (let offset = rows - 1; offset > 0 && (baseIndex + period - offset) < strLength; --offset) {
result.push(inputStr[baseIndex + period - offset]);
}
}
}
}
return result.join('');
};
Visualization Aid
The matrix representation shows string indices:
0 0+period 0+2*period
1 1+period 1+2*period
2 2+period 2+2*period
3 period-3 period-2 period-1 3+period 2*period-3 2*period-2 2*period-1 3+2*period