Off-by-one on range boundaries
Wrong move: Loop endpoints miss first/last candidate.
Usually fails on: Fails on minimal arrays and exact-boundary answers.
Fix: Re-derive loops from inclusive/exclusive ranges before coding.
Move from brute-force thinking to an efficient approach using core interview patterns strategy.
Table: patients
+-------------+---------+ | Column Name | Type | +-------------+---------+ | patient_id | int | | patient_name| varchar | | age | int | +-------------+---------+ patient_id is the unique identifier for this table. Each row contains information about a patient.
Table: covid_tests
+-------------+---------+ | Column Name | Type | +-------------+---------+ | test_id | int | | patient_id | int | | test_date | date | | result | varchar | +-------------+---------+ test_id is the unique identifier for this table. Each row represents a COVID test result. The result can be Positive, Negative, or Inconclusive.
Write a solution to find patients who have recovered from COVID - patients who tested positive but later tested negative.
Return the result table ordered by recovery_time in ascending order, then by patient_name in ascending order.
The result format is in the following example.
Example:
Input:
patients table:
+------------+--------------+-----+ | patient_id | patient_name | age | +------------+--------------+-----+ | 1 | Alice Smith | 28 | | 2 | Bob Johnson | 35 | | 3 | Carol Davis | 42 | | 4 | David Wilson | 31 | | 5 | Emma Brown | 29 | +------------+--------------+-----+
covid_tests table:
+---------+------------+------------+--------------+ | test_id | patient_id | test_date | result | +---------+------------+------------+--------------+ | 1 | 1 | 2023-01-15 | Positive | | 2 | 1 | 2023-01-25 | Negative | | 3 | 2 | 2023-02-01 | Positive | | 4 | 2 | 2023-02-05 | Inconclusive | | 5 | 2 | 2023-02-12 | Negative | | 6 | 3 | 2023-01-20 | Negative | | 7 | 3 | 2023-02-10 | Positive | | 8 | 3 | 2023-02-20 | Negative | | 9 | 4 | 2023-01-10 | Positive | | 10 | 4 | 2023-01-18 | Positive | | 11 | 5 | 2023-02-15 | Negative | | 12 | 5 | 2023-02-20 | Negative | +---------+------------+------------+--------------+
Output:
+------------+--------------+-----+---------------+ | patient_id | patient_name | age | recovery_time | +------------+--------------+-----+---------------+ | 1 | Alice Smith | 28 | 10 | | 3 | Carol Davis | 42 | 10 | | 2 | Bob Johnson | 35 | 11 | +------------+--------------+-----+---------------+
Explanation:
Output table is ordered by recovery_time in ascending order, and then by patient_name in ascending order.
Problem summary: Table: patients +-------------+---------+ | Column Name | Type | +-------------+---------+ | patient_id | int | | patient_name| varchar | | age | int | +-------------+---------+ patient_id is the unique identifier for this table. Each row contains information about a patient. Table: covid_tests +-------------+---------+ | Column Name | Type | +-------------+---------+ | test_id | int | | patient_id | int | | test_date | date | | result | varchar | +-------------+---------+ test_id is the unique identifier for this table. Each row represents a COVID test result. The result can be Positive, Negative, or Inconclusive. Write a solution to find patients who have recovered from COVID - patients who tested positive but later tested negative. A patient is considered recovered if they have at least one Positive test followed by at least one Negative test on a later date Calculate the recovery
Start with the most direct exhaustive search. That gives a correctness anchor before optimizing.
Pattern signal: General problem-solving
{"headers":{"patients":["patient_id","patient_name","age"],"covid_tests":["test_id","patient_id","test_date","result"]},"rows":{"patients":[[1,"Alice Smith",28],[2,"Bob Johnson",35],[3,"Carol Davis",42],[4,"David Wilson",31],[5,"Emma Brown",29]],"covid_tests":[[1,1,"2023-01-15","Positive"],[2,1,"2023-01-25","Negative"],[3,2,"2023-02-01","Positive"],[4,2,"2023-02-05","Inconclusive"],[5,2,"2023-02-12","Negative"],[6,3,"2023-01-20","Negative"],[7,3,"2023-02-10","Positive"],[8,3,"2023-02-20","Negative"],[9,4,"2023-01-10","Positive"],[10,4,"2023-01-18","Positive"],[11,5,"2023-02-15","Negative"],[12,5,"2023-02-20","Negative"]]}}Source-backed implementations are provided below for direct study and interview prep.
// Accepted solution for LeetCode #3586: Find COVID Recovery Patients
// Auto-generated Java example from py.
class Solution {
public void exampleSolution() {
}
}
// Reference (py):
// # Accepted solution for LeetCode #3586: Find COVID Recovery Patients
// import pandas as pd
//
//
// def find_covid_recovery_patients(
// patients: pd.DataFrame, covid_tests: pd.DataFrame
// ) -> pd.DataFrame:
// covid_tests["test_date"] = pd.to_datetime(covid_tests["test_date"])
//
// pos = (
// covid_tests[covid_tests["result"] == "Positive"]
// .groupby("patient_id", as_index=False)["test_date"]
// .min()
// )
// pos.rename(columns={"test_date": "first_positive_date"}, inplace=True)
//
// neg = covid_tests.merge(pos, on="patient_id")
// neg = neg[
// (neg["result"] == "Negative") & (neg["test_date"] > neg["first_positive_date"])
// ]
// neg = neg.groupby("patient_id", as_index=False)["test_date"].min()
// neg.rename(columns={"test_date": "first_negative_date"}, inplace=True)
//
// df = pos.merge(neg, on="patient_id")
// df["recovery_time"] = (
// df["first_negative_date"] - df["first_positive_date"]
// ).dt.days
//
// out = df.merge(patients, on="patient_id")[
// ["patient_id", "patient_name", "age", "recovery_time"]
// ]
// return out.sort_values(by=["recovery_time", "patient_name"]).reset_index(drop=True)
// Accepted solution for LeetCode #3586: Find COVID Recovery Patients
// Auto-generated Go example from py.
func exampleSolution() {
}
// Reference (py):
// # Accepted solution for LeetCode #3586: Find COVID Recovery Patients
// import pandas as pd
//
//
// def find_covid_recovery_patients(
// patients: pd.DataFrame, covid_tests: pd.DataFrame
// ) -> pd.DataFrame:
// covid_tests["test_date"] = pd.to_datetime(covid_tests["test_date"])
//
// pos = (
// covid_tests[covid_tests["result"] == "Positive"]
// .groupby("patient_id", as_index=False)["test_date"]
// .min()
// )
// pos.rename(columns={"test_date": "first_positive_date"}, inplace=True)
//
// neg = covid_tests.merge(pos, on="patient_id")
// neg = neg[
// (neg["result"] == "Negative") & (neg["test_date"] > neg["first_positive_date"])
// ]
// neg = neg.groupby("patient_id", as_index=False)["test_date"].min()
// neg.rename(columns={"test_date": "first_negative_date"}, inplace=True)
//
// df = pos.merge(neg, on="patient_id")
// df["recovery_time"] = (
// df["first_negative_date"] - df["first_positive_date"]
// ).dt.days
//
// out = df.merge(patients, on="patient_id")[
// ["patient_id", "patient_name", "age", "recovery_time"]
// ]
// return out.sort_values(by=["recovery_time", "patient_name"]).reset_index(drop=True)
# Accepted solution for LeetCode #3586: Find COVID Recovery Patients
import pandas as pd
def find_covid_recovery_patients(
patients: pd.DataFrame, covid_tests: pd.DataFrame
) -> pd.DataFrame:
covid_tests["test_date"] = pd.to_datetime(covid_tests["test_date"])
pos = (
covid_tests[covid_tests["result"] == "Positive"]
.groupby("patient_id", as_index=False)["test_date"]
.min()
)
pos.rename(columns={"test_date": "first_positive_date"}, inplace=True)
neg = covid_tests.merge(pos, on="patient_id")
neg = neg[
(neg["result"] == "Negative") & (neg["test_date"] > neg["first_positive_date"])
]
neg = neg.groupby("patient_id", as_index=False)["test_date"].min()
neg.rename(columns={"test_date": "first_negative_date"}, inplace=True)
df = pos.merge(neg, on="patient_id")
df["recovery_time"] = (
df["first_negative_date"] - df["first_positive_date"]
).dt.days
out = df.merge(patients, on="patient_id")[
["patient_id", "patient_name", "age", "recovery_time"]
]
return out.sort_values(by=["recovery_time", "patient_name"]).reset_index(drop=True)
// Accepted solution for LeetCode #3586: Find COVID Recovery Patients
// Rust example auto-generated from py reference.
// Replace the signature and local types with the exact LeetCode harness for this problem.
impl Solution {
pub fn rust_example() {
// Port the logic from the reference block below.
}
}
// Reference (py):
// # Accepted solution for LeetCode #3586: Find COVID Recovery Patients
// import pandas as pd
//
//
// def find_covid_recovery_patients(
// patients: pd.DataFrame, covid_tests: pd.DataFrame
// ) -> pd.DataFrame:
// covid_tests["test_date"] = pd.to_datetime(covid_tests["test_date"])
//
// pos = (
// covid_tests[covid_tests["result"] == "Positive"]
// .groupby("patient_id", as_index=False)["test_date"]
// .min()
// )
// pos.rename(columns={"test_date": "first_positive_date"}, inplace=True)
//
// neg = covid_tests.merge(pos, on="patient_id")
// neg = neg[
// (neg["result"] == "Negative") & (neg["test_date"] > neg["first_positive_date"])
// ]
// neg = neg.groupby("patient_id", as_index=False)["test_date"].min()
// neg.rename(columns={"test_date": "first_negative_date"}, inplace=True)
//
// df = pos.merge(neg, on="patient_id")
// df["recovery_time"] = (
// df["first_negative_date"] - df["first_positive_date"]
// ).dt.days
//
// out = df.merge(patients, on="patient_id")[
// ["patient_id", "patient_name", "age", "recovery_time"]
// ]
// return out.sort_values(by=["recovery_time", "patient_name"]).reset_index(drop=True)
// Accepted solution for LeetCode #3586: Find COVID Recovery Patients
// Auto-generated TypeScript example from py.
function exampleSolution(): void {
}
// Reference (py):
// # Accepted solution for LeetCode #3586: Find COVID Recovery Patients
// import pandas as pd
//
//
// def find_covid_recovery_patients(
// patients: pd.DataFrame, covid_tests: pd.DataFrame
// ) -> pd.DataFrame:
// covid_tests["test_date"] = pd.to_datetime(covid_tests["test_date"])
//
// pos = (
// covid_tests[covid_tests["result"] == "Positive"]
// .groupby("patient_id", as_index=False)["test_date"]
// .min()
// )
// pos.rename(columns={"test_date": "first_positive_date"}, inplace=True)
//
// neg = covid_tests.merge(pos, on="patient_id")
// neg = neg[
// (neg["result"] == "Negative") & (neg["test_date"] > neg["first_positive_date"])
// ]
// neg = neg.groupby("patient_id", as_index=False)["test_date"].min()
// neg.rename(columns={"test_date": "first_negative_date"}, inplace=True)
//
// df = pos.merge(neg, on="patient_id")
// df["recovery_time"] = (
// df["first_negative_date"] - df["first_positive_date"]
// ).dt.days
//
// out = df.merge(patients, on="patient_id")[
// ["patient_id", "patient_name", "age", "recovery_time"]
// ]
// return out.sort_values(by=["recovery_time", "patient_name"]).reset_index(drop=True)
Use this to step through a reusable interview workflow for this problem.
Two nested loops check every pair or subarray. The outer loop fixes a starting point, the inner loop extends or searches. For n elements this gives up to n²/2 operations. No extra space, but the quadratic time is prohibitive for large inputs.
Most array problems have an O(n²) brute force (nested loops) and an O(n) optimal (single pass with clever state tracking). The key is identifying what information to maintain as you scan: a running max, a prefix sum, a hash map of seen values, or two pointers.
Review these before coding to avoid predictable interview regressions.
Wrong move: Loop endpoints miss first/last candidate.
Usually fails on: Fails on minimal arrays and exact-boundary answers.
Fix: Re-derive loops from inclusive/exclusive ranges before coding.