Skip to content

LeetCode Series Problems

This document covers common LeetCode patterns involving pandas Series operations. These problems demonstrate practical applications of Series methods for data manipulation and analysis.

Pattern 1: Value Replacement with astype

LeetCode 262: Trips and Users

Problem: Calculate cancellation rate by converting status strings to binary values.

def trips_and_users(trips: pd.DataFrame, users: pd.DataFrame) -> pd.DataFrame:
    # Filter unbanned users
    banned_users = users[users['banned'] == 'Yes']['users_id']
    filtered_trips = trips[
        ~trips['client_id'].isin(banned_users) & 
        ~trips['driver_id'].isin(banned_users)
    ]

    # Convert status to binary: cancelled=1, completed=0
    cancelled = filtered_trips['status'].replace({
        'cancelled_by_driver': 1,
        'cancelled_by_client': 1,
        'completed': 0
    }).astype(int)

    # Calculate cancellation rate
    cancellation_rate = cancelled.sum() / len(cancelled)
    return cancellation_rate

Key Concepts: - replace() maps categorical values to numeric - astype(int) ensures consistent integer type - Series arithmetic for rate calculation

Pattern 2: Boolean Filtering with isin

LeetCode 183: Customers Who Never Order

Problem: Find customers not present in orders table.

def find_customers(customers: pd.DataFrame, orders: pd.DataFrame) -> pd.DataFrame:
    # Find customers whose id is NOT in orders
    no_orders = customers[~customers['id'].isin(orders['customerId'])]
    return no_orders[['name']].rename(columns={'name': 'Customers'})

Key Concepts: - isin() checks membership in another Series - ~ negates boolean Series - Boolean indexing filters DataFrame

Step-by-Step Breakdown

# Sample data
customers = pd.DataFrame({
    'id': [1, 2, 3],
    'name': ['Alice', 'Bob', 'Charlie']
})
orders = pd.DataFrame({'customerId': [1, 3]})

# Step 1: Check membership
mask = customers['id'].isin(orders['customerId'])
print(mask)  # True, False, True

# Step 2: Negate to find non-members
mask = ~mask
print(mask)  # False, True, False

# Step 3: Filter
result = customers[mask]
print(result)  # Bob (id=2)

Pattern 3: Missing Value Detection with isna/isnull

LeetCode 608: Tree Node

Problem: Classify tree nodes as Root, Inner, or Leaf.

def tree_node(tree: pd.DataFrame) -> pd.DataFrame:
    # Root: p_id is null
    tree.loc[tree['p_id'].isna(), 'type'] = 'Root'

    # Inner: has parent AND has children
    has_children = tree['id'].isin(tree['p_id'])
    tree.loc[has_children & tree['p_id'].notna(), 'type'] = 'Inner'

    # Leaf: has parent but no children
    tree.loc[~has_children & tree['p_id'].notna(), 'type'] = 'Leaf'

    return tree[['id', 'type']]

Key Concepts: - isna() detects missing values - notna() detects non-missing values - .loc[] for conditional assignment

LeetCode 1965: Employees With Missing Information

Problem: Find employees with incomplete records.

def employees_with_missing_info(
    employees: pd.DataFrame, 
    salaries: pd.DataFrame
) -> pd.DataFrame:
    # Merge with outer join
    merged = employees.merge(salaries, on='employee_id', how='outer')

    # Find rows with any missing value
    missing = merged[merged.isna().any(axis=1)]

    return missing[['employee_id']].sort_values('employee_id')

Key Concepts: - isna() returns boolean DataFrame - any(axis=1) checks if any column is True per row - Boolean indexing on aggregated condition

Pattern 4: Counting with value_counts and nunique

LeetCode 570: Managers with 5+ Direct Reports

Problem: Find managers who have at least 5 direct reports.

def find_managers(employee: pd.DataFrame) -> pd.DataFrame:
    # Count direct reports per manager
    manager_counts = employee['managerId'].value_counts()

    # Filter managers with 5+ reports
    qualified = manager_counts[manager_counts >= 5].index

    # Get manager names
    return employee[employee['id'].isin(qualified)][['name']]

Key Concepts: - value_counts() counts occurrences - Index contains unique values - Filter on count threshold

LeetCode 550: Game Play Analysis IV

Problem: Calculate fraction of players who logged in on consecutive days.

def game_play_analysis(activity: pd.DataFrame) -> pd.DataFrame:
    # Get first login date per player
    first_login = activity.groupby('player_id')['event_date'].min()

    # Count total unique players
    total_players = activity['player_id'].nunique()

    # Check for next-day login
    activity['first_date'] = activity['player_id'].map(first_login)
    activity['next_day'] = activity['first_date'] + pd.Timedelta(days=1)

    # Count players with next-day login
    next_day_logins = activity[
        activity['event_date'] == activity['next_day']
    ]['player_id'].nunique()

    fraction = next_day_logins / total_players
    return pd.DataFrame({'fraction': [round(fraction, 2)]})

Key Concepts: - nunique() counts unique values - groupby().min() finds first occurrence - Date arithmetic with Timedelta

Pattern 5: String Operations

LeetCode 1667: Fix Names in a Table

Problem: Capitalize first letter, lowercase rest.

def fix_names(users: pd.DataFrame) -> pd.DataFrame:
    users['name'] = users['name'].str.capitalize()
    return users.sort_values('user_id')

LeetCode 1683: Invalid Tweets

Problem: Find tweets with content > 15 characters.

def invalid_tweets(tweets: pd.DataFrame) -> pd.DataFrame:
    return tweets[tweets['content'].str.len() > 15][['tweet_id']]

LeetCode 1873: Calculate Special Bonus

Problem: Bonus for employees with odd ID and name not starting with 'M'.

def calculate_special_bonus(employees: pd.DataFrame) -> pd.DataFrame:
    # Condition: odd ID AND name doesn't start with M
    condition = (
        (employees['employee_id'] % 2 != 0) & 
        (~employees['name'].str.startswith('M'))
    )

    # Assign bonus
    employees['bonus'] = 0
    employees.loc[condition, 'bonus'] = employees.loc[condition, 'salary']

    return employees[['employee_id', 'bonus']].sort_values('employee_id')

LeetCode 1517: Find Users With Valid E-Mails

Problem: Filter users with valid email format.

def valid_emails(users: pd.DataFrame) -> pd.DataFrame:
    pattern = r'^[A-Za-z][A-Za-z0-9_.\-]*@leetcode\.com$'
    valid = users[users['mail'].str.match(pattern)]
    return valid

LeetCode 620: Not Boring Movies

Problem: Find movies with odd ID and description not containing "boring".

def not_boring_movies(cinema: pd.DataFrame) -> pd.DataFrame:
    condition = (
        (cinema['id'] % 2 != 0) & 
        (~cinema['description'].str.contains('boring', case=False))
    )
    return cinema[condition].sort_values('rating', ascending=False)

Pattern 6: Value Replacement

LeetCode 627: Swap Salary

Problem: Swap 'm' and 'f' values in sex column.

def swap_salary(salary: pd.DataFrame) -> pd.DataFrame:
    salary['sex'] = salary['sex'].replace({'m': 'f', 'f': 'm'})
    return salary

Key Concepts: - replace() with dictionary for bidirectional swap - In-place modification of column

Pattern 7: Rolling Window

LeetCode 1321: Restaurant Growth

Problem: Calculate 7-day rolling sum of amounts.

def restaurant_growth(customer: pd.DataFrame) -> pd.DataFrame:
    # Group by date and sum amounts
    daily = customer.groupby('visited_on')['amount'].sum().reset_index()

    # Set date as index for rolling
    daily = daily.set_index('visited_on').sort_index()

    # Calculate 7-day rolling sum
    daily['rolling_sum'] = daily['amount'].rolling('7D').sum()

    # Filter to rows with full 7-day window
    # (at least 7 days from first date)
    min_date = daily.index.min() + pd.Timedelta(days=6)
    result = daily[daily.index >= min_date].reset_index()

    return result[['visited_on', 'rolling_sum']]

Key Concepts: - rolling('7D') creates time-based window - Requires DatetimeIndex - .sum() aggregates within window

Pattern 8: Aggregation to DataFrame

LeetCode 619: Biggest Single Number

Problem: Find the largest number that appears only once.

def biggest_single_number(my_numbers: pd.DataFrame) -> pd.DataFrame:
    # Find numbers appearing exactly once
    counts = my_numbers['num'].value_counts()
    unique = counts[counts == 1].index

    # Get max or None
    if len(unique) > 0:
        result = my_numbers[my_numbers['num'].isin(unique)]['num'].max()
    else:
        result = None

    return pd.DataFrame({'num': [result]})

Alternative using to_frame():

def biggest_single_number(my_numbers: pd.DataFrame) -> pd.DataFrame:
    unique = my_numbers.drop_duplicates(keep=False)
    return unique['num'].max().to_frame(name='num') if len(unique) > 0 \
           else pd.DataFrame({'num': [None]})

Pattern Summary

Pattern Methods Used Common Use Case
Value Replacement replace(), astype() Encoding categories
Boolean Filtering isin(), ~ Set membership
Missing Detection isna(), notna(), any() Data quality
Counting value_counts(), nunique() Frequency analysis
String Operations str.capitalize(), str.contains() Text processing
Rolling Windows rolling(), sum() Time series
Aggregation to_frame(), reset_index() Result formatting