Skip to content

Added task 3564 #820

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 27, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -10,32 +10,32 @@ class Solution {
return diffVal == 1 || (char1 == 'a' && char2 == 'z') || (char1 == 'z' && char2 == 'a')
}

fun lexicographicallySmallestString(sIn: String): String? {
fun lexicographicallySmallestString(sIn: String): String {
val nVal = sIn.length
if (nVal == 0) {
return ""
}
val remTable = Array<BooleanArray?>(nVal) { BooleanArray(nVal) }
val remTable = Array<BooleanArray>(nVal) { BooleanArray(nVal) }
var len = 2
while (len <= nVal) {
for (idx in 0..nVal - len) {
val j = idx + len - 1
if (checkPair(sIn[idx], sIn[j])) {
if (len == 2) {
remTable[idx]!![j] = true
remTable[idx][j] = true
} else {
if (remTable[idx + 1]!![j - 1]) {
remTable[idx]!![j] = true
if (remTable[idx + 1][j - 1]) {
remTable[idx][j] = true
}
}
}
if (remTable[idx]!![j]) {
if (remTable[idx][j]) {
continue
}
var pSplit = idx + 1
while (pSplit < j) {
if (remTable[idx]!![pSplit] && remTable[pSplit + 1]!![j]) {
remTable[idx]!![j] = true
if (remTable[idx][pSplit] && remTable[pSplit + 1][j]) {
remTable[idx][j] = true
break
}
pSplit += 2
Expand All @@ -52,7 +52,7 @@ class Solution {
val middleVanishes: Boolean = if (kMatch - 1 < idx + 1) {
true
} else {
remTable[idx + 1]!![kMatch - 1]
remTable[idx + 1][kMatch - 1]
}
if (middleVanishes) {
val candidate = dpArr[kMatch + 1]
Expand Down
118 changes: 118 additions & 0 deletions src/main/kotlin/g3501_3600/s3564_seasonal_sales_analysis/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
3564\. Seasonal Sales Analysis

Medium

Table: `sales`

+---------------+---------+
| Column Name | Type |
+---------------+---------+
| sale_id | int |
| product_id | int |
| sale_date | date |
| quantity | int |
| price | decimal |
+---------------+---------+
sale_id is the unique identifier for this table.
Each row contains information about a product sale including the product_id,
date of sale, quantity sold, and price per unit.

Table: `products`

+---------------+---------+
| Column Name | Type |
+---------------+---------+
| product_id | int |
| product_name | varchar |
| category | varchar |
+---------------+---------+
product_id is the unique identifier for this table.
Each row contains information about a product including its name and category.

Write a solution to find the most popular product category for each season. The seasons are defined as:

* **Winter**: December, January, February
* **Spring**: March, April, May
* **Summer**: June, July, August
* **Fall**: September, October, November

The **popularity** of a **category** is determined by the **total quantity sold** in that **season**. If there is a **tie**, select the category with the highest **total revenue** (`quantity × price`).

Return _the result table ordered by season in **ascending** order_.

The result format is in the following example.

**Example:**

**Input:**

sales table:

+---------+------------+------------+----------+-------+
| sale_id | product_id | sale_date | quantity | price |
+---------+------------+------------+----------+-------+
| 1 | 1 | 2023-01-15 | 5 | 10.00 |
| 2 | 2 | 2023-01-20 | 4 | 15.00 |
| 3 | 3 | 2023-03-10 | 3 | 18.00 |
| 4 | 4 | 2023-04-05 | 1 | 20.00 |
| 5 | 1 | 2023-05-20 | 2 | 10.00 |
| 6 | 2 | 2023-06-12 | 4 | 15.00 |
| 7 | 5 | 2023-06-15 | 5 | 12.00 |
| 8 | 3 | 2023-07-24 | 2 | 18.00 |
| 9 | 4 | 2023-08-01 | 5 | 20.00 |
| 10 | 5 | 2023-09-03 | 3 | 12.00 |
| 11 | 1 | 2023-09-25 | 6 | 10.00 |
| 12 | 2 | 2023-11-10 | 4 | 15.00 |
| 13 | 3 | 2023-12-05 | 6 | 18.00 |
| 14 | 4 | 2023-12-22 | 3 | 20.00 |
| 15 | 5 | 2024-02-14 | 2 | 12.00 |
+---------+------------+------------+----------+-------+

products table:

+------------+-----------------+----------+
| product_id | product_name | category |
+------------+-----------------+----------+
| 1 | Warm Jacket | Apparel |
| 2 | Designer Jeans | Apparel |
| 3 | Cutting Board | Kitchen |
| 4 | Smart Speaker | Tech |
| 5 | Yoga Mat | Fitness |
+------------+-----------------+----------+

**Output:**

+---------+----------+----------------+---------------+
| season | category | total_quantity | total_revenue |
+---------+----------+----------------+---------------+
| Fall | Apparel | 10 | 120.00 |
| Spring | Kitchen | 3 | 54.00 |
| Summer | Tech | 5 | 100.00 |
| Winter | Apparel | 9 | 110.00 |
+---------+----------+----------------+---------------+

**Explanation:**

* **Fall (Sep, Oct, Nov):**
* Apparel: 10 items sold (6 Jackets in Sep, 4 Jeans in Nov), revenue $120.00 (6×$10.00 + 4×$15.00)
* Fitness: 3 Yoga Mats sold in Sep, revenue $36.00
* Most popular: Apparel with highest total quantity (10)
* **Spring (Mar, Apr, May):**
* Kitchen: 3 Cutting Boards sold in Mar, revenue $54.00
* Tech: 1 Smart Speaker sold in Apr, revenue $20.00
* Apparel: 2 Warm Jackets sold in May, revenue $20.00
* Most popular: Kitchen with highest total quantity (3) and highest revenue ($54.00)
* **Summer (Jun, Jul, Aug):**
* Apparel: 4 Designer Jeans sold in Jun, revenue $60.00
* Fitness: 5 Yoga Mats sold in Jun, revenue $60.00
* Kitchen: 2 Cutting Boards sold in Jul, revenue $36.00
* Tech: 5 Smart Speakers sold in Aug, revenue $100.00
* Most popular: Tech and Fitness both have 5 items, but Tech has higher revenue ($100.00 vs $60.00)
* **Winter (Dec, Jan, Feb):**
* Apparel: 9 items sold (5 Jackets in Jan, 4 Jeans in Jan), revenue $110.00
* Kitchen: 6 Cutting Boards sold in Dec, revenue $108.00
* Tech: 3 Smart Speakers sold in Dec, revenue $60.00
* Fitness: 2 Yoga Mats sold in Feb, revenue $24.00
* Most popular: Apparel with highest total quantity (9) and highest revenue ($110.00)

The result table is ordered by season in ascending order.
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Write your MySQL query statement below
# #Medium #Database #2025_05_26_Time_505_ms_(100.00%)_Space_0.0_MB_(100.00%)
WITH cte AS (
SELECT CASE
WHEN MONTH(sale_date) IN (1, 2, 12) THEN 'Winter'
WHEN MONTH(sale_date) IN (3, 4, 5) THEN 'Spring'
WHEN MONTH(sale_date) IN (6, 7, 8) THEN 'Summer'
WHEN MONTH(sale_date) IN (9, 10, 11) THEN 'Fall'
END AS season,
category, SUM(quantity) AS total_quantity, SUM(quantity * price) AS total_revenue
FROM sales s
JOIN products p ON s.product_id = p.product_id
GROUP BY season, category
),
cte2 AS (
SELECT season, category, total_quantity, total_revenue,
RANK() OVER (PARTITION BY season ORDER BY total_quantity DESC, total_revenue DESC) AS ranking
FROM cte
)
SELECT
season, category, total_quantity, total_revenue
FROM cte2
WHERE ranking = 1
ORDER BY season ASC;
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package g3501_3600.s3564_seasonal_sales_analysis

import org.hamcrest.CoreMatchers
import org.hamcrest.MatcherAssert
import org.junit.jupiter.api.Test
import org.zapodot.junit.db.annotations.EmbeddedDatabase
import org.zapodot.junit.db.annotations.EmbeddedDatabaseTest
import org.zapodot.junit.db.common.CompatibilityMode
import java.io.BufferedReader
import java.io.FileNotFoundException
import java.io.FileReader
import java.sql.SQLException
import java.util.stream.Collectors
import javax.sql.DataSource

@EmbeddedDatabaseTest(
compatibilityMode = CompatibilityMode.MySQL,
initialSqls = [
(
"CREATE TABLE sales(sale_id INTEGER, product_id INTEGER" +
", sale_date DATE, quantity INTEGER, price DECIMAL); " +
"INSERT INTO sales (sale_id, product_id, sale_date, quantity, price) VALUES" +
"(1, 1, '2023-01-15', 5, 10.00)," +
"(2, 2, '2023-01-20', 4, 15.00)," +
"(3, 3, '2023-03-10', 3, 18.00)," +
"(4, 4, '2023-04-05', 1, 20.00)," +
"(5, 1, '2023-05-20', 2, 10.00)," +
"(6, 2, '2023-06-12', 4, 15.00)," +
"(7, 5, '2023-06-15', 5, 12.00)," +
"(8, 3, '2023-07-24', 2, 18.00)," +
"(9, 4, '2023-08-01', 5, 20.00)," +
"(10, 5, '2023-09-03', 3, 12.00)," +
"(11, 1, '2023-09-25', 6, 10.00)," +
"(12, 2, '2023-11-10', 4, 15.00)," +
"(13, 3, '2023-12-05', 6, 18.00)," +
"(14, 4, '2023-12-22', 3, 20.00)," +
"(15, 5, '2024-02-14', 2, 12.00);" +
"CREATE TABLE products(product_id INTEGER, product_name VARCHAR(255)" +
", category VARCHAR(255)); " +
"INSERT INTO products (product_id, product_name, category) VALUES" +
"(1, 'Warm Jacket', 'Apparel')," +
"(2, 'Designer Jeans', 'Apparel')," +
"(3, 'Cutting Board', 'Kitchen')," +
"(4, 'Smart Speaker', 'Tech')," +
"(5, 'Yoga Mat', 'Fitness');"
),
],
)
internal class MysqlTest {
@Test
@Throws(SQLException::class, FileNotFoundException::class)
fun testScript(@EmbeddedDatabase dataSource: DataSource) {
dataSource.connection.use { connection ->
connection.createStatement().use { statement ->
statement.executeQuery(
BufferedReader(
FileReader(
(
"src/main/kotlin/g3501_3600/" +
"s3564_seasonal_sales_analysis/" +
"script.sql"
),
),
)
.lines()
.collect(Collectors.joining("\n"))
.replace("#.*?\\r?\\n".toRegex(), ""),
).use { resultSet ->
MatcherAssert.assertThat<Boolean>(resultSet.next(), CoreMatchers.equalTo<Boolean>(true))
MatcherAssert.assertThat<String>(resultSet.getNString(1), CoreMatchers.equalTo<String>("Fall"))
MatcherAssert.assertThat<String>(resultSet.getNString(2), CoreMatchers.equalTo<String>("Apparel"))
MatcherAssert.assertThat<String>(resultSet.getNString(3), CoreMatchers.equalTo<String>("10"))
MatcherAssert.assertThat<String>(resultSet.getNString(4), CoreMatchers.equalTo<String>("120"))
MatcherAssert.assertThat<Boolean>(resultSet.next(), CoreMatchers.equalTo<Boolean>(true))
MatcherAssert.assertThat<String>(resultSet.getNString(1), CoreMatchers.equalTo<String>("Spring"))
MatcherAssert.assertThat<String>(resultSet.getNString(2), CoreMatchers.equalTo<String>("Kitchen"))
MatcherAssert.assertThat<String>(resultSet.getNString(3), CoreMatchers.equalTo<String>("3"))
MatcherAssert.assertThat<String>(resultSet.getNString(4), CoreMatchers.equalTo<String>("54"))
MatcherAssert.assertThat<Boolean>(resultSet.next(), CoreMatchers.equalTo<Boolean>(true))
MatcherAssert.assertThat<String>(resultSet.getNString(1), CoreMatchers.equalTo<String>("Summer"))
MatcherAssert.assertThat<String>(resultSet.getNString(2), CoreMatchers.equalTo<String>("Tech"))
MatcherAssert.assertThat<String>(resultSet.getNString(3), CoreMatchers.equalTo<String>("5"))
MatcherAssert.assertThat<String>(resultSet.getNString(4), CoreMatchers.equalTo<String>("100"))
MatcherAssert.assertThat<Boolean>(resultSet.next(), CoreMatchers.equalTo<Boolean>(true))
MatcherAssert.assertThat<String>(resultSet.getNString(1), CoreMatchers.equalTo<String>("Winter"))
MatcherAssert.assertThat<String>(resultSet.getNString(2), CoreMatchers.equalTo<String>("Apparel"))
MatcherAssert.assertThat<String>(resultSet.getNString(3), CoreMatchers.equalTo<String>("9"))
MatcherAssert.assertThat<String>(resultSet.getNString(4), CoreMatchers.equalTo<String>("110"))
MatcherAssert.assertThat<Boolean>(resultSet.next(), CoreMatchers.equalTo<Boolean>(false))
}
}
}
}
}