In this post, I'll be going through the Detect Capital problem, day 1 of LeetCode's August daily challenge (which can be found here).
The problem is as follows:
Given a word, you need to judge whether the usage of capitals in it is right or not.
We define the usage of capitals in a word to be right when one of the following cases holds:
- All letters in this word are capitals, like "USA".
- All letters in this word are not capitals, like "leetcode".
- Only the first letter in this word is capital, like "Google".
Otherwise, we define that this word doesn't use capitals in a right way.
Note: The input will be a non-empty word consisting of uppercase and lowercase latin letters.
The approach I decided to take to this problem was to check the word character by character against each of the three "valid" patterns (as described in the problem above):
- All characters must be uppercase
- All characters must be lowercase
- The first character is uppercase, and the rest are lowercase
If the word matched any of the three valid patterns, then return true
and if not, return false
.
function detectCapitalUse(word) {
const allUpperCase = (str) => {
for(const s of str) {
if(s.toLowerCase() === s) {
return false;
}
}
return true;
}
const allLowerCase = (str) => {
for(const s of str) {
if(s.toUpperCase() === s) {
return false;
}
}
return true;
}
const matchCondition1 = allUpperCase(word);
if(matchCondition1) {
return true;
}
const matchCondition2 = allLowerCase(word);
if(matchCondition2) {
return true;
}
[first, ...rest] = word;
const matchCondition3 = (first.toUpperCase() === first) && allLowerCase(rest);
if(matchCondition3) {
return true;
}
return false;
}
As you can see, I created three variables: matchCondition1
, matchCondition2
and matchCondition3
corresponding to the three valid patterns. Each condition is checked and we return true
immediately if the word matches that particular pattern - for example, if a word is all capitals, I don't need to check the other two patterns, I already know that the word is valid and so I can return true
at that point.
I also decided to separate out the methods which check if all characters are uppercase or lowercase. I felt this made the code more readable as I do this repeatedly. Let's dive in to these methods a little bit, and look at allUpperCase
. It takes in a string and iterates over each character using a for...of
loop which gives us the value of each character (this is different to a for...in
loop which would give us the index). For each character, I check whether it is lowercase: if it is, I break out of the loop and return false
, otherwise, return true
(because it means that every character must be uppercase). Again, I purposely chose to use a for...of
loop because it allows me to abort the loop, which you can't do using a forEach
. By aborting the loop as soon as I encounter a lowercase letter, I know that I am not performing any unnecessary operations - if one letter is not uppercase, that is enough for me to know that they are not all uppercase.
As you might've guessed, allLowerCase
is doing the same thing, except that it checks whether a character is uppercase, and returns false
if it encounters any characters that are, and true
if it doesn't.
And that's it! We have solved this problem 🎉
Time complexity: O(n) where n is the word length. At worst, we need to check each character in the word 3 times.
Space complexity: O(1) . We only need constant space to store our variables.
Top comments (1)
Hello! Great post, here's my solution:
const firstUpperRestUnder = (string) => /^[A-Z]{1}[a-z]$/.test(string);
const allUpper = (string) => /^[A-Z]$/.test(string);
const allUnder = (string) => /^[a-z]*$/.test(string);
const validCapital = (string) => firstUpperRestUnder(string) || allUpper(string) || allUnder(string);
console.log(validCapital('Ireland')); // return true
console.log(validCapital('Cassio')); // return true
console.log(validCapital('abcDef')); // return false
console.log(validCapital('programing')); // return true