LeetCode 2026 - Low-Quality Problems
The problem gives us a database table named Problems. Each row represents a LeetCode problem and contains three columns:
Difficulty: 🟢 Easy
Topics: Database
Solution
Problem Understanding
The problem gives us a database table named Problems. Each row represents a LeetCode problem and contains three columns:
| Column | Meaning |
|---|---|
problem_id |
Unique identifier for the problem |
likes |
Number of users who liked the problem |
dislikes |
Number of users who disliked the problem |
We must identify all problems whose like percentage is strictly less than 60%.
The like percentage is defined as:
$$\frac{\text{likes}}{\text{likes} + \text{dislikes}} \times 100$$
A problem is considered low-quality if this percentage is less than 60.
The output should contain only the problem_id values of such problems, sorted in ascending order.
This is fundamentally a filtering problem. For every row in the table, we compute the ratio of likes to total votes and check whether it falls below the threshold.
The input scale is very small compared to algorithm-heavy problems because this is a SQL database problem. We are not dealing with millions of operations in code. Instead, the focus is on correctly expressing the filtering condition in SQL.
An important observation is that the condition is strictly less than 60%. If a problem has exactly 60% likes, it should not be included in the result.
Another subtle point is integer division. In SQL, dividing integers may truncate decimals depending on the database system. A naive implementation using integer division can produce incorrect results. We must ensure decimal arithmetic is used.
The problem guarantees that each row has a valid problem_id, and the total votes are meaningful. Since the percentage formula divides by (likes + dislikes), we assume the denominator is nonzero.
Approaches
Brute Force Approach
The brute-force way is to process every row one by one, compute the like percentage manually, and then collect all rows where the percentage is below 60.
Conceptually, this means:
- Read every row from the table.
- Compute:
$$\frac{\text{likes}}{\text{likes} + \text{dislikes}} \times 100$$
3. Compare the result against 60.
4. Keep matching problem_id values.
5. Sort the final result.
This approach is correct because every problem is independently evaluated against the exact definition of a low-quality problem.
However, in database systems, manually iterating row by row outside SQL is inefficient and unnecessary. Databases are optimized for declarative filtering operations using WHERE clauses.
Optimal Approach
The key insight is that SQL databases are designed to efficiently filter rows using arithmetic expressions directly inside the query.
Instead of external iteration, we can express the condition directly:
likes / (likes + dislikes) < 0.6
To avoid integer division issues, we convert one operand into a decimal value:
likes * 1.0 / (likes + dislikes)
This guarantees floating-point arithmetic.
The database engine evaluates the condition for each row internally and returns only the matching rows.
Approach Comparison
| Approach | Time Complexity | Space Complexity | Notes |
|---|---|---|---|
| Brute Force | O(n) | O(n) | Iterates manually through all rows and stores results |
| Optimal | O(n) | O(1) | Uses SQL filtering directly in the database engine |
Algorithm Walkthrough
- Start by selecting rows from the
Problemstable. - For each row, compute the like ratio using:
$$\frac{\text{likes}}{\text{likes} + \text{dislikes}}$$
3. Convert the division into floating-point arithmetic by multiplying likes by 1.0. This prevents integer truncation.
4. Compare the computed ratio against 0.6.
5. Keep only rows where the ratio is strictly less than 0.6.
6. Return only the problem_id column.
7. Sort the output by problem_id in ascending order.
Why it works
The algorithm directly implements the mathematical definition of a low-quality problem. Every row is checked independently using the exact percentage condition. Since SQL evaluates the filtering condition for all rows, every qualifying problem is included exactly once, and every non-qualifying problem is excluded.
Python Solution
Although this is a database problem and normally solved with SQL, the equivalent Python logic can be written as follows.
from typing import List
class Solution:
def lowQualityProblems(
self,
problems: List[List[int]]
) -> List[int]:
result: List[int] = []
for problem_id, likes, dislikes in problems:
total_votes = likes + dislikes
like_ratio = likes / total_votes
if like_ratio < 0.6:
result.append(problem_id)
result.sort()
return result
The implementation iterates through every problem entry and computes the like ratio using floating-point division.
The variable total_votes stores the denominator, which is the total number of likes and dislikes combined.
The variable like_ratio represents the fraction of users who liked the problem.
If the ratio is strictly less than 0.6, the problem_id is appended to the result list.
Finally, the result is sorted before returning, matching the required output ordering.
For the actual LeetCode database submission, the SQL query is:
SELECT problem_id
FROM Problems
WHERE likes * 1.0 / (likes + dislikes) < 0.6
ORDER BY problem_id;
Go Solution
package main
import (
"sort"
)
type Solution struct{}
func (s Solution) lowQualityProblems(problems [][]int) []int {
result := []int{}
for _, problem := range problems {
problemID := problem[0]
likes := problem[1]
dislikes := problem[2]
totalVotes := likes + dislikes
likeRatio := float64(likes) / float64(totalVotes)
if likeRatio < 0.6 {
result = append(result, problemID)
}
}
sort.Ints(result)
return result
}
The Go version follows the same logic as the Python implementation.
One important Go-specific detail is explicit type conversion. Integer division in Go truncates decimals, so both operands must be converted to float64 before division.
The result slice is dynamically expanded using append, and sort.Ints is used to ensure ascending order.
For the actual LeetCode database solution, the SQL remains:
SELECT problem_id
FROM Problems
WHERE likes * 1.0 / (likes + dislikes) < 0.6
ORDER BY problem_id;
Worked Examples
Example 1
Input table:
| problem_id | likes | dislikes |
|---|---|---|
| 6 | 1290 | 425 |
| 11 | 2677 | 8659 |
| 1 | 4446 | 2760 |
| 7 | 8569 | 6086 |
| 13 | 2050 | 4164 |
| 10 | 9002 | 7446 |
We process each row individually.
| problem_id | likes | dislikes | total_votes | like_ratio | Low Quality? |
|---|---|---|---|---|---|
| 6 | 1290 | 425 | 1715 | 0.7522 | No |
| 11 | 2677 | 8659 | 11336 | 0.2361 | Yes |
| 1 | 4446 | 2760 | 7206 | 0.6169 | No |
| 7 | 8569 | 6086 | 14655 | 0.5847 | Yes |
| 13 | 2050 | 4164 | 6214 | 0.3299 | Yes |
| 10 | 9002 | 7446 | 16448 | 0.5473 | Yes |
Collected low-quality IDs:
[11, 7, 13, 10]
After sorting:
[7, 10, 11, 13]
Final output:
| problem_id |
|---|
| 7 |
| 10 |
| 11 |
| 13 |
Complexity Analysis
| Measure | Complexity | Explanation |
|---|---|---|
| Time | O(n) | Each problem row is processed once |
| Space | O(1) | Aside from output storage, only constant extra memory is used |
The database query scans all rows exactly once and applies a constant-time arithmetic computation to each row. No additional data structures are required.
Test Cases
def low_quality(problems):
result = []
for problem_id, likes, dislikes in problems:
if likes / (likes + dislikes) < 0.6:
result.append(problem_id)
return sorted(result)
# Provided example
assert low_quality([
[6, 1290, 425],
[11, 2677, 8659],
[1, 4446, 2760],
[7, 8569, 6086],
[13, 2050, 4164],
[10, 9002, 7446]
]) == [7, 10, 11, 13] # standard mixed case
# Exactly 60%, should NOT be included
assert low_quality([
[1, 60, 40]
]) == [] # strict inequality check
# Below 60%
assert low_quality([
[1, 59, 41]
]) == [1] # just below threshold
# Above 60%
assert low_quality([
[1, 61, 39]
]) == [] # just above threshold
# Single row low quality
assert low_quality([
[5, 1, 9]
]) == [5] # extremely low ratio
# Single row high quality
assert low_quality([
[5, 9, 1]
]) == [] # extremely high ratio
# Multiple unsorted IDs
assert low_quality([
[10, 1, 9],
[2, 2, 8],
[7, 9, 1]
]) == [2, 10] # verifies sorting
# All low quality
assert low_quality([
[1, 1, 9],
[2, 2, 8],
[3, 3, 7]
]) == [1, 2, 3] # every row qualifies
# No low-quality problems
assert low_quality([
[1, 10, 1],
[2, 20, 2]
]) == [] # empty result
Test Summary
| Test | Why |
|---|---|
| Provided example | Verifies standard functionality |
| Exactly 60% | Ensures strict inequality is handled correctly |
| Just below 60% | Validates boundary inclusion |
| Just above 60% | Validates boundary exclusion |
| Single low-quality row | Tests minimal qualifying input |
| Single high-quality row | Tests minimal non-qualifying input |
| Unsorted IDs | Confirms final sorting behavior |
| All low-quality | Ensures every row can qualify |
| No low-quality rows | Ensures empty output works correctly |
Edge Cases
Problems With Exactly 60% Likes
A common mistake is using <= 0.6 instead of < 0.6. The problem explicitly states that low-quality problems must have a percentage strictly less than 60%.
For example:
likes = 60
dislikes = 40
The ratio is exactly 0.6, so this problem must not appear in the result.
The implementation correctly uses a strict comparison.
Integer Division Errors
In many SQL engines and programming languages, dividing integers truncates decimal values.
For example:
1 / 2 = 0
instead of:
0.5
If integer division is used accidentally, many ratios become incorrect, leading to wrong filtering results.
The SQL solution avoids this by using:
likes * 1.0 / (likes + dislikes)
which forces floating-point arithmetic.
Empty Result Set
It is possible that no problems satisfy the low-quality condition.
For example:
[1, 10, 1]
[2, 20, 2]
Both problems have like percentages greater than 60%.
The implementation correctly returns an empty result without errors or special-case handling.