LeetCode 1527 - Patients With a Condition

The problem asks us to query a database table Patients and return the records of patients who have Type I Diabetes. Each

LeetCode Problem 1527

Difficulty: 🟢 Easy
Topics: Database

Solution

Problem Understanding

The problem asks us to query a database table Patients and return the records of patients who have Type I Diabetes. Each patient record includes a patient_id, patient_name, and a conditions column. The conditions column may contain zero or more condition codes separated by spaces. A patient has Type I Diabetes if any of their condition codes starts with the prefix DIAB1.

In simpler terms, the task is to scan each patient's conditions string, check if at least one word begins with DIAB1, and if so, include that patient in the output. The output should contain the same columns as the input table and can be returned in any order.

Important constraints include that patient_id is unique and conditions may be empty. Edge cases to consider include patients with no conditions, patients whose conditions include similar prefixes like DIAB2, and multiple conditions in a single string.

Approaches

The brute-force approach would involve splitting each patient's conditions string into individual words and checking each word to see if it starts with DIAB1. While simple, this requires scanning every word for every patient and might be inefficient if the dataset is large.

The optimal approach leverages SQL string functions. Specifically, using LIKE with wildcards allows us to detect if DIAB1 appears at the start of a word within the string. By including spaces before and after the condition string (or handling edge positions separately), we can safely match DIAB1 at the start of any word without manually splitting strings.

Approach Time Complexity Space Complexity Notes
Brute Force O(n * m) O(1) Scan each patient and each condition word individually
Optimal O(n) O(1) Use SQL pattern matching with LIKE to find DIAB1 prefixed codes

Algorithm Walkthrough

  1. Select the columns patient_id, patient_name, and conditions from the Patients table.
  2. Use the SQL WHERE clause to filter only the rows that contain DIAB1 at the start of a word in conditions.
  3. To ensure we match DIAB1 at word boundaries, we either prepend/append a space to the conditions string or use SQL patterns with wildcards and space characters.
  4. Return the filtered rows.

Why it works: Every patient whose conditions include a word starting with DIAB1 will satisfy the LIKE condition, so the query correctly captures all Type I Diabetes patients. Patients without any matching code are automatically excluded.

Python Solution

# Python solution using SQL execution context
import sqlite3
from typing import List, Tuple

def patients_with_diabetes(conn: sqlite3.Connection) -> List[Tuple[int, str, str]]:
    query = """
    SELECT patient_id, patient_name, conditions
    FROM Patients
    WHERE ' ' || conditions || ' ' LIKE '% DIAB1%' 
    """
    cursor = conn.cursor()
    cursor.execute(query)
    return cursor.fetchall()

Explanation: We prepend and append a space to conditions so that a match at the beginning or end of the string is handled. The LIKE '% DIAB1%' ensures that DIAB1 is at the start of a word. The function executes the query and returns all matching rows.

Go Solution

package main

import (
    "database/sql"
    _ "github.com/mattn/go-sqlite3"
)

func PatientsWithDiabetes(db *sql.DB) ([][3]string, error) {
    query := `
        SELECT patient_id, patient_name, conditions
        FROM Patients
        WHERE ' ' || conditions || ' ' LIKE '% DIAB1%'
    `
    rows, err := db.Query(query)
    if err != nil {
        return nil, err
    }
    defer rows.Close()

    var result [][3]string
    for rows.Next() {
        var id int
        var name, cond string
        if err := rows.Scan(&id, &name, &cond); err != nil {
            return nil, err
        }
        result = append(result, [3]string{string(rune(id)), name, cond})
    }
    return result, nil
}

Explanation: Go uses the same SQL logic. We use db.Query to execute the query, iterate over the rows, scan values into variables, and append them to a result slice. Integer IDs are converted to string for uniform output handling in the slice.

Worked Examples

Example input:

+------------+--------------+--------------+
| patient_id | patient_name | conditions   |
+------------+--------------+--------------+
| 1          | Daniel       | YFEV COUGH   |
| 2          | Alice        |              |
| 3          | Bob          | DIAB100 MYOP |
| 4          | George       | ACNE DIAB100 |
| 5          | Alain        | DIAB201      |
+------------+--------------+--------------+

Step 1: Check each patient's conditions string:

  • Daniel: YFEV COUGH → no word starts with DIAB1 → exclude.
  • Alice: `` → empty → exclude.
  • Bob: DIAB100 MYOPDIAB100 starts with DIAB1 → include.
  • George: ACNE DIAB100DIAB100 starts with DIAB1 → include.
  • Alain: DIAB201 → starts with DIAB2 → exclude.

Output:

+------------+--------------+--------------+
| patient_id | patient_name | conditions   |
+------------+--------------+--------------+
| 3          | Bob          | DIAB100 MYOP |
| 4          | George       | ACNE DIAB100 | 
+------------+--------------+--------------+

Complexity Analysis

Measure Complexity Explanation
Time O(n) Each patient row is scanned once by the SQL engine.
Space O(1) No extra space used aside from query execution.

This is efficient because the SQL engine performs string matching internally, avoiding manual parsing in application code.

Test Cases

# provided example
assert patients_with_diabetes(conn) == [(3, 'Bob', 'DIAB100 MYOP'), (4, 'George', 'ACNE DIAB100')]

# edge case: no patients
assert patients_with_diabetes(conn_empty) == []

# edge case: all patients have DIAB1
assert patients_with_diabetes(conn_all_diab1) == [
    (1, 'Anna', 'DIAB123'), 
    (2, 'Ben', 'DIAB145 DIAB156')
]

# edge case: DIAB1 appears as substring in another word
assert patients_with_diabetes(conn_substring) == [
    (2, 'Ben', 'ACNE DIAB100')
]
Test Why
Provided example Validates standard case with mixed patients
No patients Checks function handles empty table
All patients have DIAB1 Confirms all valid matches are included
DIAB1 as substring Ensures matching occurs only at word boundaries

Edge Cases

One edge case is an empty conditions column. Without careful handling, the LIKE query could fail or include unwanted rows. Prepending and appending spaces ensures that empty strings do not match DIAB1.

Another edge case is a condition code like DIAB12XYZ versus DIAB2. The algorithm correctly only matches codes that start with DIAB1 because LIKE '% DIAB1%' enforces the prefix at word boundaries.

A third edge case is multiple conditions in one string, e.g., ACNE DIAB100 MYOP. The algorithm correctly identifies DIAB100 among other words and includes the patient, demonstrating robustness against multiple-word conditions.