1. Unique Email Addresses

From 929. Unique Email Addresses

1.1 Problem Description

Every valid email consists of a local name and a domain name, separated by the '@'sign. Besides lowercase letters, the email may contain one or more '.' or '+'.

  • For example, in "alice@leetcode.com", "alice" is the local name, and "leetcode.com" is the domain name.

If you add periods '.' between some characters in the local name part of an email address, mail sent there will be forwarded to the same address without dots in the local name. Note that this rule does not apply to domain names.

  • For example, "alice.z@leetcode.com" and "alicez@leetcode.com" forward to the same email address.

If you add a plus '+' in the local name, everything after the first plus sign will be ignored. This allows certain emails to be filtered. Note that this rule does not apply to domain names.

  • For example, "m.y+name@email.com" will be forwarded to "my@email.com".

It is possible to use both of these rules at the same time.

Given an array of strings emails where we send one email to each emails[i], return the number of different addresses that actually receive mails.

1.2 Solution

We can use split() and replace here:

  • split() is to split email address using @ as identifier
  • replace is to use "" to replace .
class Solution:
    def numUniqueEmails(self, emails: List[str]) -> int:
        actual = set()
        for email in emails:
            local, domain = email.split('@')
            local = local.split('+')[0].replace('.', '')
            actual.add((local, domain))
        return len(actual)

2. Day of the Year

From 1154. Day of the Year

2.1 Problem Description

Given a string date representing a Gregorian calendar date formatted as YYYY-MM-DD, return the day number of the year.

A leap year:

  • can be divided by 4, 400
  • cannot be divided by 100

2.2 Solution

class Solution:
    def dayOfYear(self, date: str) -> int:
        
        # data's type is string, we want to 1)split it into 3 prats: year, month, day; 2) type from string to int
        # we can use map()
        y, m, d = map(int, date.split('-'))
        
        days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
        if (y % 400) == 0 or ((y % 4 == 0) and (y % 100 != 0)): days[1] = 29
        return d + sum(days[:m-1])

3. Rotate String

From 796. Rotate String

3.1 Problem Description

Given two strings s and goal, return true if and only if s can become goal after some number of shifts on s.

A shift on s consists of moving the leftmost character of s to the rightmost position.

  • For example, if s = "abcde", then it will be "bcdea" after one shift.

Example 1:

Input: s = "abcde", goal = "cdeab"
Output: true

Example 2:

Input: s = "abcde", goal = "abced"
Output: false

3.2 Solution

One easy way to solve this problem is we can find out that string goal is also in s + s if goal is rotated from s.

class Solution:
    def rotateString(self, s: str, goal: str) -> bool:
        return len(s) == len(goal) and goal in s + s

4. Most Common Word

From 819. Most Common Word

4.1 Problem Description

Given a string paragraph and a string array of the banned words banned, return the most frequent word that is not banned. It is guaranteed there is at least one word that is not banned, and that the answer is unique.

The words in paragraph are case-insensitive and the answer should be returned in lowercase.

Example 1:

Input: paragraph = "Bob hit a ball, the hit BALL flew far after it was hit.", banned = ["hit"]
Output: "ball"
Explanation: 
"hit" occurs 3 times, but it is a banned word.
"ball" occurs twice (and no other word does), so it is the most frequent non-banned word in the paragraph. 
Note that words in the paragraph are not case sensitive,
that punctuation is ignored (even if adjacent to words, such as "ball,"), 
and that "hit" isn't the answer even though it occurs more because it is banned.

4.2 Solution

4 steps:

  1. remove all punctuations
  2. change to lowercase
  3. words count for each word not in banned set
  4. return the most common word
class Solution:
    def mostCommonWord(self, paragraph: str, banned: List[str]) -> str:
        ban = set(banned)
        # \w: Matches Unicode word characters, + means Repetition qualifiers
        words = re.findall(r'\w+', paragraph.lower())
        print(words)
        # most_common(n most common elements)
        return collections.Counter(w for w in words if w not in ban).most_common(1)[0][0]