Skip to content

Conversation

@vikahaze
Copy link
Collaborator

@vikahaze vikahaze commented Dec 21, 2025

Summary

This PR adds solutions and explanations for 10 LeetCode problems, including one accepted solution and comprehensive documentation for all problems.

Problems Added

✅ Accepted Solutions

  • Problem 955: Delete Columns to Make Sorted II (Medium) - ✅ Accepted 147/147 test cases
    • Greedy approach with sorted pair tracking
    • Time: O(M × N), Space: O(M)

Solutions with Explanations

  • Problem 3784: Minimum Deletion Cost to Make All Characters Equal (Medium)

    • Greedy: keep character with max deletion cost
    • Time: O(n), Space: O(1)
  • Problem 3783: Mirror Distance of an Integer (Easy)

    • Reverse digits and calculate absolute difference
    • Time: O(log n), Space: O(log n)
  • Problem 3781: Maximum Score After Binary Swaps (Medium)

    • Greedy with max heap
    • Time: O(n log n), Space: O(n)
  • Problem 3780: Maximum Sum of Three Numbers Divisible by Three (Medium)

    • Group by remainder, check valid combinations
    • Time: O(n log n), Space: O(n)
  • Problem 3779: Minimum Number of Operations to Have Distinct Elements (Medium)

    • Process from right to left with set tracking
    • Time: O(n), Space: O(n)
  • Problem 3776: Minimum Moves to Balance Circular Array (Medium)

    • Greedy expansion from negative index
    • Time: O(n), Space: O(1)
  • Problem 3775: Reverse Words With Same Vowel Count (Medium)

    • Count vowels and reverse matching words
    • Time: O(n), Space: O(n)
  • Problem 3774: Absolute Difference Between Maximum and Minimum K Elements (Easy)

    • Sort and calculate difference
    • Time: O(n log n), Space: O(1)
  • Problem 3716: Find Churn Risk Customers (Medium) - SQL

    • Fixed solution: changed event_type <> 'cancel' to monthly_amount > 0
    • Includes both .sql and .py files for frontend display
    • Time: O(n log n), Space: O(n)

Changes

  • ✅ 10 Python solutions (1 SQL with both .sql and .py)
  • ✅ 10 detailed explanations following template structure
  • ✅ Updated data/leetcode-problems.json with metadata for all problems
  • ✅ All explanations include Strategy and Steps sections with trace walkthroughs

Notes

  • Problem 955 was successfully submitted and accepted
  • Other problems had submission API issues ("Problem not found") but solutions are complete and ready
  • Problem 3716 SQL solution was fixed based on test case analysis
  • All solutions follow best practices and include comprehensive explanations

Summary by Sourcery

Add implemented solutions and explanations for several LeetCode problems, including one SQL/Python hybrid, and update existing implementations and explanations for clarity and correctness.

New Features:

  • Add Python solution and detailed explanation for problem 955 (minimum column deletions to ensure lexicographically sorted strings).
  • Add Python solutions and detailed explanations for problems 3784, 3783, 3781, 3780, and 3779 covering string, integer, heap, modulo, and array-processing tasks.
  • Add SQL solution for problem 3716 with a Python wrapper for execution in the frontend environment.

Bug Fixes:

  • Correct the SQL logic for churn risk customers in problem 3716 by tightening active-subscription, downgrade, tenure, and revenue-drop conditions.
  • Fix the algorithm and explanation for problem 3776 to use a linear-time outward-expansion strategy around the negative index instead of a distance-sorting approach.

Enhancements:

  • Simplify and clarify the Python implementations for problems 3775 and 3774, including in-place sorting and streamlined vowel counting.
  • Refine explanations for problems 3776, 3775, and 3774 to better align with the implemented algorithms and highlight edge cases and complexity.

Summary by CodeRabbit

  • New Features

    • Added 6 new problems (IDs 3779–3784) with metadata to the problem database.
    • Added multiple new Python solutions implementing approaches for the new problems.
  • Documentation

    • Added comprehensive explanations and step-by-step walkthroughs for many problems (including 3774–3784, 955).
  • Chores / Style

    • Minor whitespace and formatting cleanups across solution files.
  • Behavioral tweaks

    • Small algorithmic/return-value adjustments in a few solutions for clarity and consistency.

✏️ Tip: You can customize this high-level summary in your review settings.

…80, 3779, 3776, 3775, 3774, 3716

- Problem 955: Delete Columns to Make Sorted II (Accepted)
- Problem 3784: Minimum Deletion Cost to Make All Characters Equal
- Problem 3783: Mirror Distance of an Integer
- Problem 3781: Maximum Score After Binary Swaps
- Problem 3780: Maximum Sum of Three Numbers Divisible by Three
- Problem 3779: Minimum Number of Operations to Have Distinct Elements
- Problem 3776: Minimum Moves to Balance Circular Array
- Problem 3775: Reverse Words With Same Vowel Count
- Problem 3774: Absolute Difference Between Maximum and Minimum K Elements
- Problem 3716: Find Churn Risk Customers (SQL - fixed solution)

All problems include:
- Python solutions (SQL problems also include .sql and .py files)
- Detailed explanations following the template structure
- Updated metadata in leetcode-problems.json
@sourcery-ai
Copy link
Contributor

sourcery-ai bot commented Dec 21, 2025

Reviewer's Guide

Adds 10 new LeetCode solutions (9 Python + 1 SQL with Python wrapper), detailed English explanations for each, updates problem metadata, and refactors some existing implementations (notably for problems 3776, 3775, 3774, and 3716) for clarity, correctness, and efficiency.

Class diagram for new and updated LeetCode solution implementations

classDiagram

class Solution_955 {
  +minDeletionSize(strs: List[str]) int
}

class Solution_3784 {
  +minCost(s: str, cost: List[int]) int
}

class Solution_3783 {
  +mirrorDistance(n: int) int
}

class Solution_3781 {
  +maximumScore(nums: List[int], s: str) int
}

class Solution_3780 {
  +maximumSum(nums: List[int]) int
}

class Solution_3779 {
  +minOperations(nums: List[int]) int
}

class Solution_3776 {
  +minMoves(balance: List[int]) int
}

class Solution_3775 {
  +reverseWords(s: str) str
}

class Solution_3774 {
  +absDifference(nums: List[int], k: int) int
}

class ChurnRiskService_3716 {
  +find_churn_risk_customers(subscription_events: DataFrame) DataFrame
}

%% All Solution_* classes are independent, problem-specific implementations
Solution_955 ..> Solution_3784 : independent
Solution_955 ..> Solution_3783 : independent
Solution_955 ..> Solution_3781 : independent
Solution_955 ..> Solution_3780 : independent
Solution_955 ..> Solution_3779 : independent
Solution_955 ..> Solution_3776 : independent
Solution_955 ..> Solution_3775 : independent
Solution_955 ..> Solution_3774 : independent
Solution_955 ..> ChurnRiskService_3716 : independent
Loading

Flow diagram for SQL-based churn risk customer detection (problem 3716)

flowchart TD

    A["subscription_events table"] --> B["Compute query_cte with per-user aggregates
- max_event_date
- current_plan and monthly_amount
- max_historical_amount
- days_as_subscriber"]

    B --> C["Filter to latest events per user
(event_date = max_event_date)"]

    C --> D["Keep only active subscriptions
(monthly_amount > 0)"]

    D --> E["Ensure user has at least one downgrade
(EXISTS downgrade in query_cte)"]

    E --> F["Require tenure >= 60 days
(days_as_subscriber >= 60)"]

    F --> G["Require current MRR < 50% of historical max
(monthly_amount / max_historical_amount < 0.5)"]

    G --> H["Output churn risk customers
user_id, current_plan,
current_monthly_amount,
max_historical_amount,
days_as_subscriber
(sorted by days_as_subscriber DESC, user_id)"]
Loading

File-Level Changes

Change Details Files
Implement greedy O(M×N) solution for LeetCode 955 (Delete Columns to Make Sorted II) with pairwise sorted tracking and corresponding explanation.
  • Introduce minDeletionSize that scans columns left-to-right, tracking which adjacent string pairs are already sorted.
  • On each column, delete it if it breaks lexicographic order for any unsorted pair; otherwise update sorted status for pairs made strictly ordered by this column.
  • Document the algorithm, complexity, and a step-by-step trace in a new explanation file.
solutions/955/01.py
explanations/955/en.md
Implement solution and explanation for Minimum Deletion Cost to Make All Characters Equal using per-character cost aggregation.
  • Add minCost that aggregates deletion costs per character, keeps the character with maximum total cost, and deletes all others.
  • Use a defaultdict to build character→total_cost map and compute answer as total_cost_all - max_char_cost.
  • Provide an English explanation with strategy, complexity, and a worked example.
solutions/3784/01.py
explanations/3784/en.md
Implement solution and explanation for Maximum Sum of Three Numbers Divisible by Three using remainder grouping.
  • Group numbers by remainder modulo 3 and sort each bucket in descending order.
  • Compute candidate sums from four valid remainder patterns (three 0s, three 1s, three 2s, or one of each 0/1/2) and return the max valid sum.
  • Add explanation describing the grouping logic, candidate enumeration, and example trace.
solutions/3780/01.py
explanations/3780/en.md
Implement solution and explanation for Maximum Score After Binary Swaps using a max-heap over seen values.
  • Maintain a max-heap of nums values seen so far while scanning left-to-right.
  • Whenever s[i] == '1', pop the current maximum from the heap and add it to the score.
  • Document the greedy rationale, heap usage, and trace over an example in the explanation.
solutions/3781/01.py
explanations/3781/en.md
Implement solution and explanation for Minimum Number of Operations to Have Distinct Elements by scanning from right to left with set tracking.
  • Process nums from right to left, building a set of seen values and popping from a working copy.
  • On encountering the first duplicate, compute required operations as ceil(remaining_length / 3) via (len(nums)+2)//3.
  • Provide explanation showing right-to-left reasoning and sample trace.
solutions/3779/01.py
explanations/3779/en.md
Implement solution and explanation for Mirror Distance of an Integer via string reversal.
  • Define mirrorDistance to reverse digits using string slicing and compute absolute difference between original and reversed.
  • Keep implementation O(log n) in digits and very compact.
  • Explain the approach, constraints, and a simple example in the explanation file.
solutions/3783/01.py
explanations/3783/en.md
Refine Reverse Words With Same Vowel Count solution and explanation for clarity and simplicity.
  • Inline vowel counting logic using a comprehension over 'aeiou' instead of a helper and slightly simplify iteration over words.
  • Handle empty input by returning an empty string explicitly.
  • Update explanation to restate the problem more precisely, clarify constraints, and provide a more structured trace table.
solutions/3775/01.py
explanations/3775/en.md
Refine Absolute Difference Between Maximum and Minimum K Elements solution and explanation, and slightly optimize implementation.
  • Change implementation to sort the array in-place and compute sums directly over the first and last k elements.
  • Simplify return to a single abs() expression without intermediate variable.
  • Update explanation text with clearer restatement, explicit example steps, and slightly more precise complexity and edge-case notes.
solutions/3774/01.py
explanations/3774/en.md
Change strategy description and algorithm for Minimum Moves to Balance Circular Array (3776) while keeping explanation aligned with new O(n) outward-expansion approach.
  • Replace previous O(n log n) approach that collected/sorted positive balances with an O(n) greedy outward expansion from the unique negative index.
  • Work on a copy of the balance array, repeatedly increasing distance d and attempting to cover the negative balance using neighbors at indices (j+d)%n and (j-d)%n, accumulating cost as transfer*d.
  • Update explanation to match the new approach: revised complexity, decomposition steps, and example trace using the outward expansion model.
solutions/3776/01.py
explanations/3776/en.md
Fix Find Churn Risk Customers (3716) SQL logic and add a Python wrapper for frontend execution, plus explanation tweaks.
  • Adjust SQL WHERE clause to filter active subscriptions via monthly_amount > 0 instead of event_type <> 'cancel'.
  • Tighten churn-risk criteria: require days_as_subscriber >= 60 and current monthly_amount / max_historical_amount < 0.5 (strict inequalities aligned with tests).
  • Add Python helper that wraps the SQL query for pandas-based execution in the frontend.
  • Ensure the SQL file and Python wrapper share the same logic and ordering semantics.
solutions/3716/01.sql
solutions/3716/01.py

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@coderabbitai
Copy link

coderabbitai bot commented Dec 21, 2025

Important

Review skipped

More than 25% of the files skipped due to max files limit. The review is being skipped to prevent a low-quality review.

172 files out of 279 files are above the max files limit of 100. Please upgrade to Pro plan to get higher limits.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

The PR extends the dataset and solutions: adds new LeetCode problem entries (IDs 3779–3784), creates multiple explanation documents, adds several new Python solution implementations and a SQL-backed churn query, and refactors existing solution files for problems 3774, 3775, and 3776.

Changes

Cohort / File(s) Summary
Data: New Problem Entries
data/leetcode-problems.json
Added six new problem entries ("3779""3784") with metadata (id, category, title, difficulty, link).
Explanations: New Documents
explanations/3779/en.md, explanations/3780/en.md, explanations/3781/en.md, explanations/3783/en.md, explanations/3784/en.md, explanations/955/en.md
Added six explanation markdown files covering problem statements, constraints, approaches, complexity, and worked examples.
Explanations: Updated Documents
explanations/3774/en.md, explanations/3775/en.md, explanations/3776/en.md
Revised wording, restructured decompositions and walkthroughs, clarified complexity and edge cases.
Solutions: New Python Implementations
solutions/3779/01.py, solutions/3780/01.py, solutions/3781/01.py, solutions/3783/01.py, solutions/3784/01.py, solutions/955/01.py
Added new Solution classes / functions implementing algorithms (hash set scan, mod-3 grouping, max-heap greedy, digit reversal, cost aggregation, greedy column deletion).
Solutions: Updated Python Implementations
solutions/3774/01.py, solutions/3775/01.py, solutions/3776/01.py
Refactored implementations: in-place sorting and direct slicing (3774), inlined vowel counting and empty-string return change (3775), replaced sorted-distance greedy with outward expansion balancing (3776).
Solutions: New SQL & Python Churn Detection
solutions/3716/01.py, solutions/3716/01.sql
Added Python wrapper and SQL CTE to identify churn-risk customers; removed duplicate cancel-filter in SQL and implemented query filters for downgrades, duration, and monthly-amount ratio.
Minor formatting / whitespace fixes
solutions/3768/01.py, solutions/3769/01.py
Whitespace and formatting-only edits; no logic changes.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20–30 minutes

Areas that may need extra attention:

  • solutions/3776/01.py: algorithm change to outward expansion — verify correctness on circular edge cases and feasibility checks.
  • solutions/3716/01.py and solutions/3716/01.sql: validate CTE logic, event_type <> 'cancel' placement, assumptions about connections/parameters.
  • solutions/3775/01.py: behavior change for empty input (now returns "") and removal of helper — confirm intended semantics.
  • Newly added solution files (solutions/37793784, solutions/955): ensure compliance with expected function/class signatures and handle edge cases.

Possibly related PRs

Poem

🐰 New entries hop in, neat and spry,
Pages of problems, solutions piled high.
From mirrors to heaps and costs to scores,
I nibble bugs and neatly close doors.
hop hop 🥕✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 6.25% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: adding solutions and explanations for 10 specific LeetCode problems (955, 3784, 3783, 3781, 3780, 3779, 3776, 3775, 3774, 3716), which matches the changeset contents.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 4 issues, and left some high level feedback:

  • The new minMoves implementation for 3776 never decrements neighbor balances and adds the full storage to A[j] instead of just the transfer amount, which can both undercount cost and potentially cause an infinite loop when storage is 0; consider explicitly reducing neighbor balances by transfer and only adding transfer to A[j] (or otherwise reworking the logic) so the simulation is consistent with the explanation.
  • In solutions/3716/01.py, pd.read_sql(query, con=None) will fail at runtime if invoked; if this is intended only as a display wrapper, consider replacing the call with a clear placeholder (e.g., raising NotImplementedError) to avoid misleading behavior.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The new `minMoves` implementation for 3776 never decrements neighbor balances and adds the full `storage` to `A[j]` instead of just the `transfer` amount, which can both undercount cost and potentially cause an infinite loop when `storage` is 0; consider explicitly reducing neighbor balances by `transfer` and only adding `transfer` to `A[j]` (or otherwise reworking the logic) so the simulation is consistent with the explanation.
- In `solutions/3716/01.py`, `pd.read_sql(query, con=None)` will fail at runtime if invoked; if this is intended only as a display wrapper, consider replacing the call with a clear placeholder (e.g., raising `NotImplementedError`) to avoid misleading behavior.

## Individual Comments

### Comment 1
<location> `solutions/3776/01.py:20-29` </location>
<code_context>
-            transfer = min(remaining, amount)
-            res += transfer * dist
-            remaining -= transfer
+        # Work with a copy to avoid modifying input
+        A = balance[:]
+        res = 0
+        d = 0
+        
+        # Expand outward from negative index
+        while A[j] < 0:
+            d += 1
+            # Get storage from neighbors at distance d
+            storage = A[(j + d) % n] + A[(j - d) % n]
+            transfer = min(-A[j], storage)
+            res += transfer * d
+            A[j] += storage

         return res
</code_context>

<issue_to_address>
**issue (bug_risk):** Negative-balance adjustment loop does not conserve balances and can miscompute transfers or loop incorrectly.

Inside the `while A[j] < 0:` loop, you compute `storage` from both neighbors but only ever change `A[j]` (`A[j] += storage`), leaving the neighbor balances untouched. This breaks conservation and over-credits `A[j]`. Also, you calculate `transfer = min(-A[j], storage)` but then add `storage` instead of `transfer`, so `A[j]` can flip positive in one step when `storage > -A[j]`, and if `storage <= 0`, `A[j]` will not change, risking an infinite loop. You likely want to debit neighbors and credit `A[j]` by `transfer`, or redesign the loop so each step represents a valid transfer and guarantees progress toward zero.
</issue_to_address>

### Comment 2
<location> `solutions/3716/01.py:14-23` </location>
<code_context>
+    query = """
</code_context>

<issue_to_address>
**issue (bug_risk):** Using `pd.read_sql` with `con=None` will raise at runtime; consider making the placeholder safer or injectable.

`pd.read_sql(query, con=None)` will always error because `con` must be a real DB-API connection or SQLAlchemy engine. Since this function appears callable, consider either accepting a `con` parameter, raising `NotImplementedError` instead of invoking `read_sql`, or wrapping the call in a placeholder mechanism to avoid surprising runtime failures.
</issue_to_address>

### Comment 3
<location> `solutions/3716/01.py:5-14` </location>
<code_context>
+    """
</code_context>

<issue_to_address>
**question (bug_risk):** The "active subscription" definition in the docstring and query have slightly different semantics.

The docstring requires “last event is not cancel”, but the SQL instead uses `monthly_amount > 0` to infer an active subscription. If `cancel` (or other terminal events) can appear with non-zero or zero `monthly_amount`, this may diverge from the documented behavior. If those cases exist in your data model, consider aligning the condition with the docstring (e.g., also filtering on `event_type`).
</issue_to_address>

### Comment 4
<location> `explanations/955/en.md:54` </location>
<code_context>
+| Step | Column | Check Pair | Comparison | Breaks Order? | Action | res | sorted_pairs |
+| ---- | ------ | ---------- | ---------- | ------------- | ------ | --- | ------------ |
+| 1    | 0      | "ca"-"bb"  | 'c' > 'b'  | Yes           | Delete column 0 | 1   | [False, False] |
+| 2    | 1      | "ca"-"bb"  | 'a' < 'b'  | No            | Keep column 1, update sorted | 1   | [True, False] |
+| 2    | 1      | "bb"-"ac"  | 'b' < 'c'  | No            | Keep column 1, update sorted | 1   | [True, True] |
+
+Detailed execution:
</code_context>

<issue_to_address>
**issue (typo):** The Step column in the trace table for problem 955 repeats the value 2; the last row should likely be Step 3.

In the **2.3 Trace Walkthrough** table for `explanations/955/en.md`, both rows for column 1 are labeled `Step 2`. Please renumber the second one to `Step 3` (or otherwise fix the sequence) so the progression is unambiguous.

```suggestion
| 3    | 1      | "bb"-"ac"  | 'b' < 'c'  | No            | Keep column 1, update sorted | 1   | [True, True] |
```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +14 to +23
query = """
WITH query_cte AS (
SELECT
user_id,
event_date,
MAX(event_date) OVER(PARTITION BY user_id) max_event_date,
event_type,
plan_name current_plan,
monthly_amount,
MAX(monthly_amount) OVER(PARTITION BY user_id) max_historical_amount,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): Using pd.read_sql with con=None will raise at runtime; consider making the placeholder safer or injectable.

pd.read_sql(query, con=None) will always error because con must be a real DB-API connection or SQLAlchemy engine. Since this function appears callable, consider either accepting a con parameter, raising NotImplementedError instead of invoking read_sql, or wrapping the call in a placeholder mechanism to avoid surprising runtime failures.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

🧹 Nitpick comments (4)
solutions/3716/01.py (1)

4-4: Remove or utilize the unused subscription_events parameter.

The subscription_events parameter is declared but never used in the function body. Since this is a SQL-based solution that operates via pd.read_sql, either:

  1. Remove the parameter entirely, or
  2. Use it to populate a temporary table for the query (if that's the intended design)
🔎 Proposed fix to remove unused parameter
-def find_churn_risk_customers(subscription_events: pd.DataFrame) -> pd.DataFrame:
+def find_churn_risk_customers() -> pd.DataFrame:
explanations/3781/en.md (1)

1-65: Documentation is comprehensive and technically accurate.

The explanation clearly describes the greedy max-heap strategy with good complexity analysis and a detailed trace example.

Optional style polish: Line 5 has three consecutive sentences beginning with "We". Consider rewording for variety:

🔎 Suggested rephrase
-**Restate the problem:** We are given an integer array `nums` and a binary string `s` of the same length. Initially, score is 0. Each index where `s[i] = '1'` contributes `nums[i]` to the score. We can swap '0' and '1' if they are adjacent and '0' is before '1' (swap "01" to "10"). We can do this any number of times. We need to find the maximum possible score.
+**Restate the problem:** Given an integer array `nums` and a binary string `s` of the same length, we start with a score of 0. Each index where `s[i] = '1'` contributes `nums[i]` to the score. Adjacent '0' and '1' can be swapped if '0' precedes '1' (swap "01" to "10"), and this operation can be repeated any number of times. The goal is to find the maximum possible score.
solutions/3784/01.py (1)

3-3: Consider moving import to module level.

While importing inside the function works, it's more conventional and slightly more efficient to place imports at the module level.

🔎 Proposed refactor
 from typing import List
+from collections import defaultdict
 
 class Solution:
     def minCost(self, s: str, cost: List[int]) -> int:
-        from collections import defaultdict
-        
         # Sum up costs for each character
         char_to_cost = defaultdict(int)
explanations/955/en.md (1)

1-71: LGTM! Comprehensive explanation with clear trace walkthrough.

The documentation provides excellent coverage of the greedy column-deletion strategy. The trace table with detailed step-by-step execution is particularly helpful for understanding the sorted-pairs tracking mechanism.

Note: There's a minor style suggestion from LanguageTool about "all of the" → "all" on line 5, but this is purely stylistic and optional.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cef971c and 688f099.

📒 Files selected for processing (21)
  • data/leetcode-problems.json (1 hunks)
  • explanations/3774/en.md (1 hunks)
  • explanations/3775/en.md (1 hunks)
  • explanations/3776/en.md (1 hunks)
  • explanations/3779/en.md (1 hunks)
  • explanations/3780/en.md (1 hunks)
  • explanations/3781/en.md (1 hunks)
  • explanations/3783/en.md (1 hunks)
  • explanations/3784/en.md (1 hunks)
  • explanations/955/en.md (1 hunks)
  • solutions/3716/01.py (1 hunks)
  • solutions/3716/01.sql (1 hunks)
  • solutions/3774/01.py (1 hunks)
  • solutions/3775/01.py (1 hunks)
  • solutions/3776/01.py (1 hunks)
  • solutions/3779/01.py (1 hunks)
  • solutions/3780/01.py (1 hunks)
  • solutions/3781/01.py (1 hunks)
  • solutions/3783/01.py (1 hunks)
  • solutions/3784/01.py (1 hunks)
  • solutions/955/01.py (1 hunks)
🧰 Additional context used
🪛 LanguageTool
explanations/955/en.md

[style] ~5-~5: Consider removing “of” to be more concise
Context: ...em:** We are given an array of strings, all of the same length. We can delete any columns ...

(ALL_OF_THE)

explanations/3781/en.md

[style] ~5-~5: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ..."). We can do this any number of times. We need to find the maximum possible score...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)

🪛 Ruff (0.14.8)
solutions/3784/01.py

2-2: Undefined name List

(F821)


7-7: zip() without an explicit strict= parameter

Add explicit value for parameter strict=

(B905)

solutions/3781/01.py

2-2: Undefined name List

(F821)

solutions/3780/01.py

2-2: Undefined name List

(F821)

solutions/3779/01.py

2-2: Undefined name List

(F821)

solutions/3716/01.py

4-4: Unused function argument: subscription_events

(ARG001)

solutions/955/01.py

2-2: Undefined name List

(F821)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Sourcery review
🔇 Additional comments (21)
solutions/3716/01.sql (1)

28-29: LGTM! Thresholds are clear and mathematically sound.

The 60-day duration threshold and 50% revenue ratio are well-defined churn risk indicators. The division is safe because max_historical_amount (the MAX of all monthly_amount values) must be ≥ current monthly_amount > 0, ensuring no division by zero.

solutions/3716/01.py (2)

35-35: Verify that monthly_amount > 0 reliably identifies active subscriptions.

This Python implementation uses the same filter logic as the SQL file. As noted in the SQL review, the assumption that monthly_amount > 0 means "not cancelled" should be verified against the data schema to ensure cancelled subscriptions with positive amounts aren't incorrectly included.


46-48: Placeholder con=None is appropriately documented.

The comment clearly explains that con=None is a placeholder for the LeetCode environment. This is acceptable for a solution wrapper file intended for frontend display.

solutions/3774/01.py (1)

1-13: LGTM! Clean and efficient implementation.

The logic correctly sorts the array, extracts the k smallest and k largest elements, and returns the absolute difference. The slicing approach is idiomatic Python.

Two minor observations:

  1. List type hint requires from typing import List (though LeetCode typically provides this).
  2. nums.sort() mutates the input. If immutability is desired, use sorted(nums) instead.
solutions/3775/01.py (2)

9-16: Verify case sensitivity for vowel counting.

The vowel check only includes lowercase vowels ('aeiou'). If the problem allows uppercase letters, words like "APPLE" would count 0 vowels instead of 2.

If uppercase vowels should be counted, consider:

c.lower() in 'aeiou'

1-24: Logic is clean and correct for the stated problem.

The implementation correctly:

  1. Handles empty input by returning ""
  2. Counts vowels in the first word as the reference
  3. Reverses only subsequent words with matching vowel counts
  4. Preserves the first word unchanged
solutions/3776/01.py (1)

5-18: Assumption of single negative balance may not hold.

The algorithm finds only the first negative balance and processes it. If the problem guarantees at most one negative balance, this is fine. However, if multiple negatives can exist, this approach would miss them.

Please verify the problem constraints to confirm there's at most one negative balance in the input.

explanations/3774/en.md (1)

1-61: Clear and well-structured explanation.

The documentation accurately describes the approach, matches the implementation, and provides a helpful trace walkthrough. The complexity analysis is correct.

explanations/3776/en.md (1)

52-63: Trace walkthrough correctly shows the intended algorithm behavior.

The explanation accurately describes adding transfer (4) to the balance, resulting in -4 + 4 = 0. Note: the current code implementation has a bug where it adds storage instead of transfer (flagged separately in the code review).

explanations/3775/en.md (1)

1-62: Documentation is well-structured and clear.

The explanation follows a consistent template with clear problem restatement, complexity analysis, strategy breakdown, and a detailed trace walkthrough. The content accurately describes the vowel-counting and word-reversal algorithm.

solutions/3781/01.py (1)

3-19: Algorithm implementation is correct.

The max-heap approach using negation with Python's heapq is properly implemented. The logic correctly adds all values to the heap and pops the maximum when encountering '1' in the string.

solutions/3783/01.py (1)

1-8: Clean and correct implementation.

The digit reversal using string slicing is straightforward and matches the documented approach. The logic correctly computes the absolute difference between the number and its reverse.

explanations/3783/en.md (1)

1-62: Clear and thorough documentation.

The explanation effectively describes the mirror distance problem with accurate complexity analysis and a helpful trace walkthrough using n=25 as an example.

solutions/3780/01.py (1)

3-30: Algorithm correctly implements remainder-grouping strategy.

The solution properly groups numbers by remainder (mod 3), sorts each group in descending order, and evaluates all four valid combinations to find the maximum sum divisible by 3.

solutions/3779/01.py (1)

3-13: Implementation correctly processes right-to-left with duplicate detection.

The solution appropriately creates a copy to avoid input mutation, maintains a seen set while processing from right to left, and applies the formula (len(nums) + 2) // 3 when a duplicate is encountered.

explanations/3784/en.md (1)

1-71: Excellent documentation with clear strategy explanation.

The explanation effectively describes the greedy approach of keeping the character with maximum deletion cost. The trace walkthrough with the example clearly demonstrates how the algorithm identifies 'c' as the character to keep, resulting in a minimum cost of 11.

explanations/3780/en.md (1)

1-69: LGTM! Well-structured explanation.

The documentation provides clear strategy rationale, comprehensive step-by-step walkthrough with a trace table, proper complexity analysis, and edge case coverage. The explanation effectively guides readers through the modulo-grouping approach.

explanations/3779/en.md (1)

1-68: LGTM! Clear and thorough explanation.

The documentation effectively explains the right-to-left processing strategy with set-based duplicate detection. The trace walkthrough clearly demonstrates the algorithm flow, and the complexity analysis is accurate.

solutions/955/01.py (1)

3-24: LGTM! Correct greedy implementation.

The algorithm correctly implements the greedy approach with sorted-pair tracking:

  • Processes columns left to right
  • Checks for ordering violations only on unsorted pairs
  • Updates sorted status when columns establish strict ordering
  • Properly handles the early break when a violation is found
solutions/3784/01.py (1)

7-7: This suggestion cannot be applied without establishing Python 3.10+ as the repository's minimum version requirement.

The strict=True parameter for zip() was introduced in Python 3.10, but this repository does not specify a minimum Python version. Adding this parameter would break compatibility with Python versions earlier than 3.10. Before adopting this suggestion, ensure the project explicitly requires Python 3.10+ in its configuration (pyproject.toml, setup.py, .python-version, or similar).

Likely an incorrect or invalid review comment.

data/leetcode-problems.json (1)

26448-26482: Clarify whether problem 3782 was intentionally excluded.

The sequence jumps from 3781 to 3783, omitting 3782. Please confirm whether this is intentional (problem doesn't exist on LeetCode) or if it should be included in this PR.

Comment on lines +9 to +12
- **Input Size:** Up to 10^5 elements in the array.
- **Time Complexity:** O(n) where n is the length - we find the negative index once, then expand outward at most n/2 steps.
- **Space Complexity:** O(1) - we only use a few variables.
- **Edge Case:** If all balances are already non-negative, return 0. If the total sum is negative, return -1.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Space complexity is inconsistent with the implementation.

The explanation states O(1) space, but the solution creates a copy with A = balance[:], which is O(n) space. Consider updating the documentation to reflect the actual space usage.

🔎 Suggested fix
-- **Space Complexity:** O(1) - we only use a few variables.
+- **Space Complexity:** O(n) - we create a copy of the balance array.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- **Input Size:** Up to 10^5 elements in the array.
- **Time Complexity:** O(n) where n is the length - we find the negative index once, then expand outward at most n/2 steps.
- **Space Complexity:** O(1) - we only use a few variables.
- **Edge Case:** If all balances are already non-negative, return 0. If the total sum is negative, return -1.
- **Input Size:** Up to 10^5 elements in the array.
- **Time Complexity:** O(n) where n is the length - we find the negative index once, then expand outward at most n/2 steps.
- **Space Complexity:** O(n) - we create a copy of the balance array.
- **Edge Case:** If all balances are already non-negative, return 0. If the total sum is negative, return -1.
🤖 Prompt for AI Agents
In explanations/3776/en.md around lines 9 to 12, the doc claims O(1) space but
the implementation creates a copy with A = balance[:] (O(n)); update the Space
Complexity line to O(n) to match the code, or alternatively remove the array
copy in the implementation and operate in-place to legitimately claim O(1)
space—pick one approach and make the corresponding change (update the text to
O(n) if keeping the copy, or change code to avoid copying if you want O(1)).

Comment on lines +26 to +32
while A[j] < 0:
d += 1
# Get storage from neighbors at distance d
storage = A[(j + d) % n] + A[(j - d) % n]
transfer = min(-A[j], storage)
res += transfer * d
A[j] += storage
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Critical bug: incorrect balance update causes wrong results.

Line 32 adds storage to A[j], but it should add transfer. When transfer < storage, the debt is incorrectly over-credited, and subsequent loop iterations may behave unexpectedly.

Additionally, at larger distances d, the same neighbors may be visited multiple times (when d >= n//2), leading to double-counting of available storage.

🔎 Proposed fix
         while A[j] < 0:
             d += 1
             # Get storage from neighbors at distance d
             storage = A[(j + d) % n] + A[(j - d) % n]
             transfer = min(-A[j], storage)
             res += transfer * d
-            A[j] += storage
+            A[j] += transfer

Also consider adding a guard to stop expansion when d > n // 2 to avoid overlapping neighbors in the circular array.

🤖 Prompt for AI Agents
In solutions/3776/01.py around lines 26 to 32, the loop that tries to fill
negative A[j] incorrectly adds the full neighbor storage to A[j] (A[j] +=
storage) instead of only the actual amount transferred, and it can double-count
neighbors when d grows large; change the update to add transfer (A[j] +=
transfer) and after computing d increment/add a guard to break once d > n//2 (or
when neighbors overlap) to avoid revisiting the same pair of neighbors in the
circular array.

Comment on lines +1 to +2
class Solution:
def minOperations(self, nums: List[int]) -> int:
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Missing typing import causes undefined name error.

The type hint List[int] on line 2 requires importing List from the typing module.

🔎 Proposed fix
+from typing import List
+
 class Solution:
     def minOperations(self, nums: List[int]) -> int:
🧰 Tools
🪛 Ruff (0.14.8)

2-2: Undefined name List

(F821)

🤖 Prompt for AI Agents
In solutions/3779/01.py around lines 1 to 2, the type hint List[int] is used but
List is not imported; add "from typing import List" (or switch to built-in
"list[int]" for Python 3.9+) at the top of the file so the type name is defined
and the annotation no longer raises a NameError.

Comment on lines +1 to +2
class Solution:
def maximumSum(self, nums: List[int]) -> int:
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Missing typing import causes undefined name error.

The type hint List[int] on line 2 requires importing List from the typing module. This will cause type checking failures and potential runtime errors.

🔎 Proposed fix
+from typing import List
+
 class Solution:
     def maximumSum(self, nums: List[int]) -> int:
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
class Solution:
def maximumSum(self, nums: List[int]) -> int:
from typing import List
class Solution:
def maximumSum(self, nums: List[int]) -> int:
🧰 Tools
🪛 Ruff (0.14.8)

2-2: Undefined name List

(F821)

🤖 Prompt for AI Agents
In solutions/3780/01.py around lines 1 to 2, the function annotation uses
List[int] but List is not imported; add the typing import by importing List from
the typing module (e.g., from typing import List) at the top of the file so the
type hint is defined and type checking/runtime name resolution succeeds.

Comment on lines +1 to +2
class Solution:
def maximumScore(self, nums: List[int], s: str) -> int:
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Missing typing import causes undefined name error.

The type hint List[int] on line 2 requires importing List from the typing module. Without this import, the code will fail type checking and may raise a NameError at runtime depending on the Python version.

🔎 Proposed fix
+from typing import List
+
 class Solution:
     def maximumScore(self, nums: List[int], s: str) -> int:
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
class Solution:
def maximumScore(self, nums: List[int], s: str) -> int:
from typing import List
class Solution:
def maximumScore(self, nums: List[int], s: str) -> int:
🧰 Tools
🪛 Ruff (0.14.8)

2-2: Undefined name List

(F821)

🤖 Prompt for AI Agents
In solutions/3781/01.py around lines 1 to 2, the type hint uses List[int] but
List is not imported, causing an undefined name error; add the import from
typing (e.g., `from typing import List`) at the top of the file so the List
symbol is defined and type hints work correctly.

@@ -0,0 +1,16 @@
class Solution:
def minCost(self, s: str, cost: List[int]) -> int:
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Add missing import for List type annotation.

The List type is used in the method signature but not imported, which will cause a NameError at runtime.

🔎 Proposed fix
+from typing import List
+
 class Solution:
     def minCost(self, s: str, cost: List[int]) -> int:

Committable suggestion skipped: line range outside the PR's diff.

🧰 Tools
🪛 Ruff (0.14.8)

2-2: Undefined name List

(F821)

🤖 Prompt for AI Agents
In solutions/3784/01.py around line 2, the function signature uses the type name
List but the symbol is not imported; add the missing import by adding "from
typing import List" at the top of the file (or replace List with built-in list
in the signature) so the type annotation resolves and no NameError occurs.

@@ -0,0 +1,25 @@
class Solution:
def minDeletionSize(self, strs: List[str]) -> int:
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Add missing import for List type annotation.

The List type is used in the method signature but not imported, which will cause a NameError at runtime.

🔎 Proposed fix
+from typing import List
+
 class Solution:
     def minDeletionSize(self, strs: List[str]) -> int:
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
def minDeletionSize(self, strs: List[str]) -> int:
from typing import List
class Solution:
def minDeletionSize(self, strs: List[str]) -> int:
🧰 Tools
🪛 Ruff (0.14.8)

2-2: Undefined name List

(F821)

🤖 Prompt for AI Agents
In solutions/955/01.py around lines 2 to 2, the function signature uses the
typing name List but the module does not import it; add the missing import by
importing List from the typing module at the top of the file (e.g., from typing
import List) so the type annotation resolves and avoids a NameError.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (5)
solutions/3779/01.py (1)

1-2: Missing List import (already flagged).

This issue was already identified in previous reviews. The type hint List[int] requires importing List from the typing module (or use the built-in list[int] for Python 3.9+).

solutions/3716/01.py (1)

5-5: Address the unused parameter and runtime-error placeholder.

Two issues remain from previous reviews:

  1. Unused parameter (line 5): The subscription_events DataFrame parameter is never used. The embedded SQL queries a table named subscription_events directly, creating confusion about the function's contract.

  2. Runtime error (lines 49-51): pd.read_sql(query, con=None) will always raise an exception since con must be a valid database connection.

Consider one of these approaches:

  • Option 1 (Recommended): Remove the misleading parameter and raise NotImplementedError with a clear message that this is a SQL-only solution.
  • Option 2: Accept a con parameter and pass it through to pd.read_sql.
  • Option 3: Use the subscription_events DataFrame by creating an in-memory SQLite connection (via sqlite3 or sqlalchemy), loading the DataFrame into it, then executing the query.
🔎 Proposed fix using Option 1
-def find_churn_risk_customers(subscription_events: pd.DataFrame) -> pd.DataFrame:
+def find_churn_risk_customers() -> pd.DataFrame:
     """
     Find customers at risk of churning.
 
     A customer is at churn risk if they:
     1. Currently have an active subscription (last event is not cancel)
     2. Have performed at least one downgrade
     3. Current plan revenue < 50% of historical maximum
     4. Have been a subscriber for at least 60 days
+    
+    Note: This is a SQL-only solution for LeetCode.
+    The SQL should be executed directly in LeetCode's SQL environment.
     """
-    query = """
+    raise NotImplementedError(
+        "This is a SQL-only solution. Execute the query below in LeetCode SQL environment:\n\n"
+        """
     WITH query_cte AS (
         SELECT 
             user_id, 
@@ -44,10 +47,5 @@
         AND monthly_amount / CAST(max_historical_amount AS FLOAT) <= 0.5 
     ORDER BY days_as_subscriber DESC, user_id
     """
-    # Note: This is a SQL solution. In actual LeetCode environment,
-    # this would be executed as raw SQL, not via pandas
-    return pd.read_sql(
-        query, con=None
-    )  # Placeholder - actual execution depends on LeetCode environment
+    )

Also applies to: 49-51

solutions/3776/01.py (2)

32-32: Critical bug: incorrect balance update causes wrong results.

Line 32 adds storage to A[j], but should add transfer. When transfer < storage, the debt is incorrectly over-credited, and subsequent iterations behave unexpectedly.

🔎 Proposed fix
-            A[j] += storage
+            A[j] += transfer

26-32: Critical bug: neighbor overlap causes double-counting and incorrect results.

When d reaches n/2 (for even n) or exceeds (n-1)/2, the indices (j+d)%n and (j-d)%n either point to the same element or revisit previously accessed neighbor pairs.

Examples:

  • n=6, j=0, d=3: (j+d)%n = 3 and (j-d)%n = 3storage = 2*A[3] (same element counted twice)
  • n=6, j=0, d=4: visits neighbors (4, 2), but these were already visited at d=2 as (2, 4)

This leads to incorrect storage calculations and inflated costs.

🔎 Proposed fix

Add a guard to prevent overlap and handle the edge case when neighbors converge:

         # Expand outward from negative index
         while A[j] < 0:
             d += 1
+            # Stop if we've covered all unique neighbor pairs
+            if d > n // 2:
+                break
             # Get storage from neighbors at distance d
-            storage = A[(j + d) % n] + A[(j - d) % n]
+            left = (j - d) % n
+            right = (j + d) % n
+            # Handle case when neighbors converge to same index
+            storage = A[left] + (A[right] if left != right else 0)
             transfer = min(-A[j], storage)
             res += transfer * d
             A[j] += transfer

Note: This fix also incorporates the correction from the previous comment (using transfer instead of storage).

solutions/3781/01.py (1)

1-2: Missing List import (previously flagged).

This critical issue has already been identified in a previous review. The List[int] type hint requires importing List from the typing module.

🧹 Nitpick comments (1)
solutions/3781/01.py (1)

3-3: Consider moving import to module level.

Importing heapq inside the method works but is non-idiomatic. Module-level imports improve readability and follow PEP 8 conventions.

🔎 Suggested refactor

Move the import to the top of the file alongside the List import:

+from typing import List
+import heapq
+
 class Solution:
     def maximumScore(self, nums: List[int], s: str) -> int:
-        import heapq
-
         # Use max heap (negate values for Python's min heap)
         heap = []
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 688f099 and d0a5256.

📒 Files selected for processing (11)
  • solutions/3716/01.py (1 hunks)
  • solutions/3716/01.sql (1 hunks)
  • solutions/3768/01.py (2 hunks)
  • solutions/3769/01.py (1 hunks)
  • solutions/3774/01.py (1 hunks)
  • solutions/3775/01.py (1 hunks)
  • solutions/3776/01.py (1 hunks)
  • solutions/3779/01.py (1 hunks)
  • solutions/3780/01.py (1 hunks)
  • solutions/3781/01.py (1 hunks)
  • solutions/3783/01.py (1 hunks)
✅ Files skipped from review due to trivial changes (2)
  • solutions/3768/01.py
  • solutions/3769/01.py
🚧 Files skipped from review as they are similar to previous changes (2)
  • solutions/3783/01.py
  • solutions/3774/01.py
🧰 Additional context used
🪛 Ruff (0.14.8)
solutions/3716/01.py

5-5: Unused function argument: subscription_events

(ARG001)

solutions/3781/01.py

2-2: Undefined name List

(F821)

solutions/3780/01.py

2-2: Undefined name List

(F821)

solutions/3779/01.py

2-2: Undefined name List

(F821)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Sourcery review
🔇 Additional comments (10)
solutions/3779/01.py (1)

4-5: Verify empty list handling.

If nums is empty, nums.pop() on line 5 will raise an IndexError. Please confirm whether the problem constraints guarantee at least one element, or add a guard clause if empty lists are valid inputs.

🔎 Proposed defensive check (if needed)
     def minOperations(self, nums: List[int]) -> int:
+        if not nums:
+            return 0
+        
         # Process from right to left using a copy
         nums = nums[:]  # Work with a copy to avoid modifying input
solutions/3716/01.sql (1)

21-21: LGTM! The filter now correctly excludes cancelled subscriptions.

The change from monthly_amount > 0 to event_type <> 'cancel' properly addresses the previous review feedback. This ensures that cancelled subscriptions are excluded based on their event type rather than amount, which is the correct semantics for identifying active subscribers.

solutions/3716/01.py (1)

15-46: SQL logic correctly matches the standalone solution.

The embedded SQL query is consistent with solutions/3716/01.sql and correctly uses event_type <> 'cancel' (line 36) to filter out cancelled subscriptions. The churn-risk criteria are properly implemented.

solutions/3780/01.py (1)

3-30: Algorithm logic is correct and well-implemented.

The solution correctly identifies all four valid patterns for selecting three numbers with sum divisible by 3:

  • Three numbers with remainder 0
  • One from each remainder (0, 1, 2)
  • Three numbers with remainder 1
  • Three numbers with remainder 2

The greedy approach of selecting the largest values from each group maximizes the sum, and the implementation matches the stated O(n log n) time and O(n) space complexity.

Note: The missing List import flagged in the previous review comment must be addressed for the code to run correctly.

solutions/3775/01.py (4)

5-6: LGTM: Empty input handling is correct.

Returning an empty string for empty input is appropriate.


8-12: Verify first word reversal logic and handle uppercase vowels.

Two concerns:

  1. First word consistency: The first word is never reversed (Line 12), even though it has the same vowel count as itself. If the problem expects ALL words with matching vowel counts to be reversed, the first word should also be reversed. Please verify whether the first word should remain unchanged or be reversed like other matching words.

  2. Uppercase vowels not counted: Line 9 checks c in "aeiou", which only counts lowercase vowels. If the input contains uppercase vowels ('A', 'E', 'I', 'O', 'U'), they will be ignored, leading to incorrect vowel counts and potentially wrong word reversals.

🔎 Proposed fix for uppercase vowel handling

If uppercase vowels should be counted, update the vowel check:

-        first_word_vowels = sum(1 for c in words[0] if c in "aeiou")
+        first_word_vowels = sum(1 for c in words[0] if c.lower() in "aeiou")

14-22: Handle uppercase vowels in word processing loop.

Line 16 has the same issue: c in "aeiou" only counts lowercase vowels. If the input contains uppercase vowels, they will be ignored, leading to incorrect comparisons and word reversals.

🔎 Proposed fix for uppercase vowel handling

If uppercase vowels should be counted:

-            vowel_count = sum(1 for c in word if c in "aeiou")
+            vowel_count = sum(1 for c in word if c.lower() in "aeiou")

24-24: LGTM: String joining is correct.

The result is properly joined with spaces to reconstruct the output string.

solutions/3776/01.py (1)

5-10: No action needed. The problem guarantees that initially at most one index has a negative balance. The algorithm correctly handles this constraint by finding and processing the single negative index.

solutions/3781/01.py (1)

9-17: The algorithm correctly assumes len(nums) == len(s) based on the problem constraints, which explicitly state that both inputs have the same length. No input validation is needed.

Likely an incorrect or invalid review comment.

@romankurnovskii romankurnovskii merged commit 12d5805 into main Dec 21, 2025
3 checks passed
@romankurnovskii romankurnovskii deleted the problems-955-3784-3783-3781-3780-3779-3776-3775-3774-3716 branch December 21, 2025 09:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants