ช่วงต่อเนื่องที่ยาวที่สุดของผู้ใช้แต่ละคน
คำนวณความยาวสูงสุดของช่วงที่เกิดขึ้นต่อเนื่องภายในแต่ละกลุ่ม
ช่วงต่อเนื่องที่ยาวที่สุดของผู้ใช้แต่ละคน เป็นบทเรียน Coding Interview Prep ฟรีบน CoddyKit นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Coding Interview Prep และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Coding Interview Prep มีบทเรียนทั้งหมด 4 บทเรียน
คำถาม
คำถามต่อยอดที่พบบ่อยหลังการตรวจหาช่วงวันที่ต่อเนื่องคือ "สำหรับผู้ใช้แต่ละราย ช่วงวันที่ผู้ใช้นั้นใช้งานต่อเนื่องกัน ยาวที่สุด คือช่วงใด" ทีมผลิตภัณฑ์และทีมการเติบโตมักถามคำถามนี้เพื่อวัดการมีส่วนร่วม
คุณรู้วิธีระบุช่วงต่อเนื่องแต่ละช่วงอยู่แล้ว ขั้นตอนใหม่คือการหาความยาวสูงสุดของช่วงต่อเนื่อง สำหรับผู้ใช้แต่ละราย และบ่อยครั้งยังต้องแสดงวันที่ของช่วงต่อเนื่องที่ดีที่สุดด้วย บทเรียนนี้ต่อยอดโดยตรงจากโครงร่างช่องว่างและกลุ่มช่วงต่อเนื่อง
ทบทวนการสร้างกลุ่มช่วงต่อเนื่อง
จากบทเรียนก่อนหน้า การจัดกลุ่มแต่ละช่วงใช้ login_date - ROW_NUMBER() เป็นค่าอ้างอิงของกลุ่มช่วงต่อเนื่อง ผู้ใช้แต่ละรายอาจมีหลายกลุ่มช่วงต่อเนื่อง เราจะคำนวณให้ได้หนึ่งแถวต่อหนึ่งกลุ่มก่อน แล้วจึงลดผลลัพธ์ให้เหลือหนึ่งแถวต่อผู้ใช้
โปรดจำแผนสองชั้นนี้ไว้: ขั้นแรกสร้างกลุ่มช่วงต่อเนื่อง จากนั้นจึงรวมกลุ่มช่วงต่อเนื่องเหล่านั้น
WITH numbered AS (
SELECT user_id, login_date,
ROW_NUMBER() OVER (
PARTITION BY user_id ORDER BY login_date
) AS rn
FROM logins
)
SELECT user_id, login_date - rn AS grp
FROM numbered;หนึ่งแถวต่อหนึ่งกลุ่มช่วงต่อเนื่อง
รวมแต่ละกลุ่มช่วงต่อเนื่องให้เหลือแถวสรุปเดียว ซึ่งมีความยาวและช่วงวันที่ของกลุ่มนั้น จัดกลุ่มตามผู้ใช้และค่าอ้างอิง แล้วคำนวณตัวชี้วัด
เราตั้งชื่อ CTE นี้ว่า islands เพื่อให้ชั้นถัดไปอ่านข้อมูลได้อย่างเป็นระเบียบ
WITH numbered AS (
SELECT user_id, login_date,
ROW_NUMBER() OVER (
PARTITION BY user_id ORDER BY login_date
) AS rn
FROM logins
),
islands AS (
SELECT user_id,
MIN(login_date) AS streak_start,
MAX(login_date) AS streak_end,
COUNT(*) AS streak_len
FROM numbered
GROUP BY user_id, login_date - rn
)
SELECT * FROM islands;คำตอบแบบง่าย: ความยาวสูงสุด
หากผู้สัมภาษณ์ต้องการเพียงความยาว ขั้นตอนสุดท้ายมีเพียงบรรทัดเดียว: จัดกลุ่มกลุ่มช่วงต่อเนื่องตามผู้ใช้ แล้วหาความยาวสูงสุด
นี่คือคำตอบที่กระชับที่สุดเมื่อไม่จำเป็นต้องแสดงวันที่เริ่มต้นและวันที่สิ้นสุด
-- ...numbered and islands CTEs as before...
SELECT
user_id,
MAX(streak_len) AS longest_streak
FROM islands
GROUP BY user_id
ORDER BY user_id;แสดงวันที่ร่วมด้วย
บ่อยครั้งผู้สัมภาษณ์จะถามต่อว่า "และแสดงด้วยว่าช่วงต่อเนื่องนั้นเกิดขึ้นเมื่อใด" การใช้ MAX เพียงอย่างเดียวไม่สามารถบอกได้ว่ากลุ่มช่วงต่อเนื่องใดเป็นผู้ชนะ คุณต้อง จัดอันดับกลุ่มช่วงต่อเนื่องภายในผู้ใช้แต่ละราย แล้วเก็บอันดับที่ 1
ใช้ ROW_NUMBER โดยเรียงตามความยาวจากมากไปน้อย เพื่อให้ช่วงต่อเนื่องที่ดีที่สุดของผู้ใช้แต่ละรายได้อันดับที่ 1 เพิ่มเกณฑ์ตัดสินกรณีเสมอเพื่อให้ผลลัพธ์ถูกกำหนดอย่างแน่นอน
ROW_NUMBER() OVER (
PARTITION BY user_id
ORDER BY streak_len DESC, streak_start ASC
) AS rnkจัดอันดับและกรอง
ห่อการจัดอันดับไว้ใน CTE แล้วกรองให้เหลือ rnk = 1 คุณไม่สามารถกรองฟังก์ชันหน้าต่างโดยตรงใน WHERE ได้ ดังนั้นจึงจำเป็นต้องมีชั้นเพิ่มเติม
WITH numbered AS (
SELECT user_id, login_date,
ROW_NUMBER() OVER (
PARTITION BY user_id ORDER BY login_date
) AS rn
FROM logins
),
islands AS (
SELECT user_id,
MIN(login_date) AS streak_start,
MAX(login_date) AS streak_end,
COUNT(*) AS streak_len
FROM numbered
GROUP BY user_id, login_date - rn
),
ranked AS (
SELECT *,
ROW_NUMBER() OVER (
PARTITION BY user_id
ORDER BY streak_len DESC, streak_start
) AS rnk
FROM islands
)
SELECT user_id, streak_start, streak_end, streak_len
FROM ranked
WHERE rnk = 1;RANK เทียบกับ ROW_NUMBER เมื่อเสมอกัน
ถ้าผู้ใช้รายหนึ่งมีช่วงต่อเนื่องที่ยาวที่สุดเท่ากันสองช่วง และผู้สัมภาษณ์ต้องการให้แสดง ทั้งสองช่วง จะทำอย่างไร ให้เปลี่ยน ROW_NUMBER เป็น RANK แล้วเก็บ rnk = 1
ROW_NUMBER— มีผู้ชนะเพียงหนึ่งช่วงต่อผู้ใช้ (ผลลัพธ์กรณีเสมอจะไม่แน่นอนหากไม่เพิ่มเกณฑ์ตัดสิน)RANK— ช่วงต่อเนื่องที่ยาวที่สุดและเสมอกันทั้งหมดจะได้อันดับที่ 1 และถูกเก็บไว้ทั้งหมด
ระบุให้ชัดว่าผู้สัมภาษณ์ต้องการพฤติกรรมแบบใด เพราะแสดงให้เห็นว่าคุณใส่ใจกับกรณีขอบ
RANK() OVER (
PARTITION BY user_id
ORDER BY streak_len DESC
) AS rnk -- keep all rnk = 1ตัวอย่างที่ทำให้ดู
สมมติว่าผู้ใช้ 7 เข้าสู่ระบบวันที่ 1-4 มกราคม จากนั้นวันที่ 10-11 มกราคม แล้วจึงวันที่ 20-23 มกราคม จะมีกลุ่มช่วงต่อเนื่องสามกลุ่มที่มีความยาว 4, 2 และ 4 วัน ความยาวสูงสุดคือ 4 วัน และมีช่วงที่เสมอกัน
- เมื่อใช้
ROW_NUMBERร่วมกับเกณฑ์ตัดสินstreak_start: จะแสดงเฉพาะช่วงวันที่ 1-4 มกราคม - เมื่อใช้
RANK: จะแสดงทั้งช่วงวันที่ 1-4 มกราคมและช่วงวันที่ 20-23 มกราคม
การกล่าวประเด็นนี้ออกมาแสดงให้เห็นว่าคุณได้พิจารณาเรื่องรายการซ้ำแล้ว
การจัดการผู้ใช้ที่ไม่เคยเข้าสู่ระบบ
ผู้สัมภาษณ์อาจถามว่า: "แล้วผู้ใช้ที่ไม่เคยเข้าสู่ระบบเลยล่ะ?" ผู้ใช้เหล่านั้นไม่มีแถวใน logins จึงหายไปจากผลลัพธ์ หากต้องแสดงผู้ใช้เหล่านั้นพร้อมช่วงต่อเนื่องเป็น 0 ให้ใช้ LEFT JOIN กับตาราง users ทั้งตาราง และใช้ COALESCE
SELECT u.user_id,
COALESCE(MAX(i.streak_len), 0) AS longest_streak
FROM users u
LEFT JOIN islands i ON i.user_id = u.user_id
GROUP BY u.user_id;หมายเหตุด้านประสิทธิภาพ
รูปแบบนี้อ่านข้อมูลตามลำดับหนึ่งรอบ แล้วจัดกลุ่มอีกหนึ่งครั้ง เพื่อให้ทำงานได้รวดเร็ว:
- ตรวจสอบให้มีดัชนีบน
(user_id, login_date)เพื่อให้ ORDER BY ของหน้าต่างไม่ต้องเรียงลำดับใหม่ - กำจัดข้อมูลซ้ำตั้งแต่ต้น หากแหล่งข้อมูลมีเหตุการณ์หลายรายการต่อวัน
- หลีกเลี่ยงการครอบ
login_dateด้วยฟังก์ชันใน ORDER BY เพราะอาจทำให้ใช้ดัชนีไม่ได้
สำหรับตารางขนาดใหญ่มาก วิธีนี้ทำงานได้เร็วกว่าวิธีเชื่อมตารางกับตัวเองอย่างชัดเจน
คำตอบฉบับเต็มสำหรับการสัมภาษณ์
นี่คือคำสั่งสอบถามฉบับสมบูรณ์และเรียบเรียงอย่างดี ซึ่งคืนค่าช่วงต่อเนื่องที่ยาวที่สุดของผู้ใช้แต่ละคนพร้อมวันที่ของช่วงนั้น — เป็นเวอร์ชันที่ควรเขียนบนกระดาน
WITH numbered AS (
SELECT user_id, login_date,
ROW_NUMBER() OVER (
PARTITION BY user_id ORDER BY login_date
) AS rn
FROM logins
),
islands AS (
SELECT user_id,
MIN(login_date) AS streak_start,
MAX(login_date) AS streak_end,
COUNT(*) AS streak_len
FROM numbered
GROUP BY user_id, login_date - rn
),
ranked AS (
SELECT *,
ROW_NUMBER() OVER (
PARTITION BY user_id
ORDER BY streak_len DESC, streak_start
) AS rnk
FROM islands
)
SELECT user_id, streak_start, streak_end, streak_len
FROM ranked
WHERE rnk = 1
ORDER BY user_id;ตรวจสอบอย่างรวดเร็ว
เลือกเครื่องมือที่เหมาะสมกับข้อกำหนด
สรุป
การคำนวณช่วงต่อเนื่องที่ยาวที่สุดของผู้ใช้แต่ละคน:
- สร้างกลุ่มช่วงต่อเนื่องด้วยจุดยึด
login_date - ROW_NUMBER() - ยุบแต่ละกลุ่มให้เหลือความยาวและช่วงวันที่
- หากต้องการเฉพาะความยาว ให้จัดกลุ่มตามผู้ใช้แล้วใช้
MAX(streak_len) - หากต้องการวันที่ด้วย ให้จัดอันดับกลุ่มช่วงต่อเนื่องภายในผู้ใช้แต่ละคน แล้วเก็บอันดับที่ 1 — ใช้
RANKเพื่อรวมกรณีที่เสมอกัน และใช้ROW_NUMBERเมื่อต้องการผู้ชนะเพียงหนึ่งราย - ใช้ LEFT JOIN กับ users เพื่อแสดงผู้ใช้ที่มีช่วงต่อเนื่องเป็นศูนย์
ถัดไป: การตรวจหาจำนวนแถวต่อเนื่อง N แถวที่ตรงตามเงื่อนไข
คำถามที่พบบ่อย
บทเรียน “ช่วงต่อเนื่องที่ยาวที่สุดของผู้ใช้แต่ละคน” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “ช่วงต่อเนื่องที่ยาวที่สุดของผู้ใช้แต่ละคน” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Coding Interview Prep ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Coding Interview Prep มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “ช่วงต่อเนื่องที่ยาวที่สุดของผู้ใช้แต่ละคน”
คำนวณความยาวสูงสุดของช่วงที่เกิดขึ้นต่อเนื่องภายในแต่ละกลุ่ม คุณปฏิบัติ Coding Interview Prep ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Coding Interview Prep หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน Coding Interview Prep บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน
บทเรียน “ช่วงต่อเนื่องที่ยาวที่สุดของผู้ใช้แต่ละคน” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน Coding Interview Prep นี้ได้ไหม
ได้ บทเรียน Coding Interview Prep ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- ตรวจจับวันที่ในปฏิทินที่ต่อเนื่องกัน
- ช่วงต่อเนื่องที่ยาวที่สุดของผู้ใช้แต่ละคน
- แถวต่อเนื่อง N แถวที่ตรงตามเงื่อนไข
- ช่วงต่อเนื่องที่ยังดำเนินอยู่จนถึงวันนี้