Day 1/31: Detect Capital
Tags: leetcode, javascript, algorithms
Published: 2020-08-02 17:48:53

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](https://leetcode.com/explore/challenge/card/august-leetcoding-challenge/549/week-1-august-1st-august-7th/3409/)).

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:
>
> 1. All letters in this word are capitals, like "USA".
> 2. All letters in this word are not capitals, like "leetcode".
> 3. 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):

1. All characters must be uppercase
2. All characters must be lowercase
3. 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`.

```js
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 :tada:

---

**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.