Given a list of strings words
, where each string represents a row in a word square, determine if the input forms a valid word square.
A word square is valid if and only if the kth row and kth column read the exact same string for all valid k (0-indexed). In other words, for every position (i, j)
in the square, words[i][j]
must equal words[j][i]
whenever both are defined.
words[i]
can have different lengths.words[i][j]
or words[j][i]
to be undefined (if the row or column is too short).true
if the square is valid, and false
otherwise.Constraints:
words.length
≤ 500words[i].length
≤ 500At first glance, the problem seems to require checking that the input forms a perfect square (same number of rows and columns, and all strings of equal length). However, since each row can have different lengths, we need to be more careful.
The key insight is: for each character at position (i, j)
in the 2D grid, it must match the character at position (j, i)
, if both exist. If either words[i][j]
or words[j][i]
is missing, the square is not valid.
A brute-force solution would be to loop over every possible (i, j)
pair, but that could be inefficient. Instead, we can iterate over the rows and columns up to the maximum length, checking for mismatches or missing characters.
This is similar to checking if a matrix is symmetric along its main diagonal, with the added twist that some rows might be shorter than others.
We'll validate the word square by comparing each character at position (i, j)
with its "transpose" at (j, i)
. Here's how:
i
: For each row, loop through each character j
in words[i]
.
words[i][j]
, ensure that words[j]
exists (i.e., j < len(words)
) and that words[j][i]
exists (i.e., i < len(words[j])
).
words[i][j]
equals words[j][i]
. If not, return false
.
true
at the end.
We use direct index checks to avoid index out-of-bounds errors and to ensure that the word square is well-formed.
Example Input:
words = ["abcd",
"bnrt",
"crmy",
"dtye"]
Let's walk through the validation:
true
.
Counter-Example Input:
words = ["ball",
"area",
"read",
"lady"]
false
.
class Solution:
def validWordSquare(self, words: List[str]) -> bool:
n = len(words)
for i in range(n):
for j in range(len(words[i])):
if j >= n or i >= len(words[j]) or words[i][j] != words[j][i]:
return False
return True
class Solution {
public:
bool validWordSquare(vector<string>& words) {
int n = words.size();
for (int i = 0; i < n; ++i) {
for (int j = 0; j < words[i].size(); ++j) {
if (j >= n || i >= words[j].size() || words[i][j] != words[j][i])
return false;
}
}
return true;
}
};
class Solution {
public boolean validWordSquare(List<String> words) {
int n = words.size();
for (int i = 0; i < n; ++i) {
String row = words.get(i);
for (int j = 0; j < row.length(); ++j) {
if (j >= n || i >= words.get(j).length() || row.charAt(j) != words.get(j).charAt(i)) {
return false;
}
}
}
return true;
}
}
var validWordSquare = function(words) {
let n = words.length;
for (let i = 0; i < n; i++) {
for (let j = 0; j < words[i].length; j++) {
if (j >= n || i >= words[j].length || words[i][j] !== words[j][i]) {
return false;
}
}
}
return true;
};
(i, j)
in a full 2D grid of size N x M
, time complexity could be up to O(N * M), where N is the number of rows and M is the maximum row length.
The solution is efficient because it avoids unnecessary checks and does not use extra memory for data structures.
The Valid Word Square problem is a neat exercise in matrix symmetry and careful index handling. By iterating over each character and checking its "transpose" counterpart, we ensure that the word square property holds. The solution is both simple and robust, handling cases where rows may be of different lengths and ensuring no out-of-bounds errors. The approach is optimal in both time and space, making it a great example of clean, efficient coding.