|
| 1 | +# **550. Game Play Analysis IV** |
| 2 | + |
| 3 | +## **Problem Statement** |
| 4 | +You are given a table named `Activity`, which logs the gaming activity of players. |
| 5 | + |
| 6 | +### **Activity Table** |
| 7 | +```rb |
| 8 | ++--------------+---------+ |
| 9 | +| Column Name | Type | |
| 10 | ++--------------+---------+ |
| 11 | +| player_id | int | |
| 12 | +| device_id | int | |
| 13 | +| event_date | date | |
| 14 | +| games_played | int | |
| 15 | ++--------------+---------+ |
| 16 | +``` |
| 17 | +- **(player_id, event_date)** is the **primary key**. |
| 18 | +- Each row contains: |
| 19 | + - `player_id`: The ID of the player. |
| 20 | + - `event_date`: The date when the player logged in. |
| 21 | + - `games_played`: The number of games played before logging out. |
| 22 | + |
| 23 | +### **Task:** |
| 24 | +Find the **fraction** of players who logged in **again** the day after their **first login date**, rounded to **2 decimal places**. |
| 25 | + |
| 26 | +--- |
| 27 | + |
| 28 | +## **Example 1:** |
| 29 | +### **Input:** |
| 30 | +#### **Activity Table** |
| 31 | +```rb |
| 32 | ++-----------+-----------+------------+--------------+ |
| 33 | +| player_id | device_id | event_date | games_played | |
| 34 | ++-----------+-----------+------------+--------------+ |
| 35 | +| 1 | 2 | 2016-03-01 | 5 | |
| 36 | +| 1 | 2 | 2016-03-02 | 6 | |
| 37 | +| 2 | 3 | 2017-06-25 | 1 | |
| 38 | +| 3 | 1 | 2016-03-02 | 0 | |
| 39 | +| 3 | 4 | 2018-07-03 | 5 | |
| 40 | ++-----------+-----------+------------+--------------+ |
| 41 | +``` |
| 42 | +### **Output:** |
| 43 | +```rb |
| 44 | ++-----------+ |
| 45 | +| fraction | |
| 46 | ++-----------+ |
| 47 | +| 0.33 | |
| 48 | ++-----------+ |
| 49 | +``` |
| 50 | +### **Explanation:** |
| 51 | +- `player_id = 1`: First login on **2016-03-01**, logs in again on **2016-03-02** ✅ |
| 52 | +- `player_id = 2`: First login on **2017-06-25**, no next-day login ❌ |
| 53 | +- `player_id = 3`: First login on **2016-03-02**, no next-day login ❌ |
| 54 | + |
| 55 | +Total players = **3**, Players who logged in the next day = **1** → **1 / 3 = 0.33** ✅ |
| 56 | + |
| 57 | +--- |
| 58 | + |
| 59 | +## **Solution Approaches** |
| 60 | + |
| 61 | +### **SQL Solution (Using `JOIN` & `DATEDIFF`)** |
| 62 | +```sql |
| 63 | +SELECT |
| 64 | + ROUND(( |
| 65 | + SELECT COUNT(DISTINCT a.player_id) |
| 66 | + FROM Activity a |
| 67 | + INNER JOIN ( |
| 68 | + SELECT player_id, MIN(event_date) AS first_login |
| 69 | + FROM Activity |
| 70 | + GROUP BY player_id |
| 71 | + ) b |
| 72 | + ON a.player_id = b.player_id |
| 73 | + AND DATEDIFF(a.event_date, b.first_login) = 1 |
| 74 | + ) / |
| 75 | + (SELECT COUNT(DISTINCT player_id) FROM Activity), 2) AS fraction; |
| 76 | +``` |
| 77 | +**Explanation:** |
| 78 | +1. **Find First Login Date per Player** |
| 79 | + - `MIN(event_date) AS first_login` |
| 80 | + - **Grouped by** `player_id` |
| 81 | +2. **Find Players Who Logged in on the Next Day** |
| 82 | + - **Join** the table with itself. |
| 83 | + - Use `DATEDIFF(a.event_date, b.first_login) = 1` to check next-day logins. |
| 84 | + - Count unique `player_id`s. |
| 85 | +3. **Calculate Fraction** |
| 86 | + - Divide by total distinct `player_id`s. |
| 87 | + - Round to **2 decimal places**. |
| 88 | + |
| 89 | +--- |
| 90 | + |
| 91 | +### **Alternative SQL Solution (Using `EXISTS`)** |
| 92 | +```sql |
| 93 | +SELECT ROUND( |
| 94 | + (SELECT COUNT(DISTINCT player_id) |
| 95 | + FROM Activity a |
| 96 | + WHERE EXISTS ( |
| 97 | + SELECT 1 FROM Activity b |
| 98 | + WHERE a.player_id = b.player_id |
| 99 | + AND DATEDIFF(b.event_date, a.event_date) = 1 |
| 100 | + )) / |
| 101 | + (SELECT COUNT(DISTINCT player_id) FROM Activity), 2) AS fraction; |
| 102 | +``` |
| 103 | +**Explanation:** |
| 104 | +- Checks if a player has **ANY** login exactly **one day after**. |
| 105 | +- Uses `EXISTS` to optimize performance. |
| 106 | + |
| 107 | +--- |
| 108 | + |
| 109 | +### **Pandas Solution** |
| 110 | +```python |
| 111 | +import pandas as pd |
| 112 | + |
| 113 | +def game_play_analysis(activity: pd.DataFrame) -> pd.DataFrame: |
| 114 | + # Get first login date for each player |
| 115 | + first_login = activity.groupby("player_id")["event_date"].min().reset_index() |
| 116 | + first_login.columns = ["player_id", "first_login"] |
| 117 | + |
| 118 | + # Merge first login date with original table |
| 119 | + merged = activity.merge(first_login, on="player_id") |
| 120 | + |
| 121 | + # Filter players who logged in the next day |
| 122 | + next_day_logins = merged[ |
| 123 | + (merged["event_date"] - merged["first_login"]).dt.days == 1 |
| 124 | + ]["player_id"].nunique() |
| 125 | + |
| 126 | + # Total unique players |
| 127 | + total_players = activity["player_id"].nunique() |
| 128 | + |
| 129 | + # Calculate fraction |
| 130 | + fraction = round(next_day_logins / total_players, 2) |
| 131 | + |
| 132 | + return pd.DataFrame({"fraction": [fraction]}) |
| 133 | +``` |
| 134 | +**Explanation:** |
| 135 | +1. **Find First Login Date** |
| 136 | + - Group by `player_id`, get `min(event_date)`. |
| 137 | +2. **Merge with Original Table** |
| 138 | + - Check if `event_date - first_login = 1 day`. |
| 139 | +3. **Count Unique Players** |
| 140 | + - Divide by total unique `player_id`s. |
| 141 | + |
| 142 | +--- |
| 143 | + |
| 144 | +## **File Structure** |
| 145 | +``` |
| 146 | +📂 LeetCode550 |
| 147 | +│── 📜 problem_statement.md |
| 148 | +│── 📜 sql_solution.sql |
| 149 | +│── 📜 sql_exists_solution.sql |
| 150 | +│── 📜 pandas_solution.py |
| 151 | +│── 📜 README.md |
| 152 | +``` |
| 153 | +- `problem_statement.md` → Contains the problem description. |
| 154 | +- `sql_solution.sql` → SQL solution using **JOIN & DATEDIFF**. |
| 155 | +- `sql_exists_solution.sql` → SQL solution using **EXISTS**. |
| 156 | +- `pandas_solution.py` → Pandas solution. |
| 157 | +- `README.md` → Overview of problem and solutions. |
| 158 | + |
| 159 | +--- |
| 160 | + |
| 161 | +## **Useful Links** |
| 162 | +- [LeetCode Problem 550](https://leetcode.com/problems/game-play-analysis-iv/) |
| 163 | +- [SQL `DATEDIFF()`](https://www.w3schools.com/sql/func_mysql_datediff.asp) |
| 164 | +- [Pandas `.groupby()`](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.groupby.html) |
0 commit comments