ภาพรวมปัญหา
ให้รายการตัวเลขและขนาดหน้าต่าง k เราต้องหาค่ามัธยฐาน (median) ของแต่ละหน้าต่างที่เลื่อนไปทีละหนึ่งตำแหน่งจากซ้ายไปขวา
ตัวอย่าง
อาเรย์: [1, 3, -1, -3, 5, 3, 6, 8], k = 3
| ตำแหน่งหน้าต่าง | ค่ามัธยฐาน |
|---|---|
| [1, 3, -1] | 1 |
| [3, -1, -3] | -1 |
| [-1, -3, 5] | -1 |
| [-3, 5, 3] | 3 |
| [5, 3, 6] | 5 |
| [3, 6, 8] | 6 |
ผลลัพธ์: [1, -1, -1, 3, 5, 6]
วิธีแก้ปัญหา
ใช้ Multiset (BST แบบสมดุล) เพื่อจัดเก็บองค์ประกอบในหน้าต่างปัจจุบัน เนื่องจาก Multiset จัดเก็บข้อมูลเรียงลำดับอัตโนมัติ จึงสามารถหาค่ามัธยฐานได้ในเวลา O(log k)
ขั้นตอนหลัก
- สร้าง Multiset
arrเพื่อเก็บค่าในหน้าต่าง - ฟังก์ชัน
insert(x): เพิ่มxเข้าarr - ฟังก์ชัน
delete_(x): ลบxออกจากarr(ถ้ามีอยู่) - ฟังก์ชัน
getMedian():- ให้
n = arr.size() - หาตำแหน่งกลาง:
a = *next(arr.begin(), n/2 - 1),b = *next(arr.begin(), n/2) - ถ้า
nเป็นคี่ → คืนค่าb - ถ้า
nเป็นคู่ → คืนค่า(a + b) * 0.5
- ให้
- เติมองค์ประกอบ
kตัวแรกเข้าarr - เลื่อนหน้าต่าง: ลบองค์ประกอบเก่าออก เพิ่มองค์ประกอบใหม่เข้า แล้วบันทึกค่ามัธยฐาน
โค้ด C++
#include <bits/stdc++.h>
using namespace std;
void print_vector(vector<double> v) {
cout << "[";
for (int i = 0; i < v.size(); i++) {
cout << v[i] << ", ";
}
cout << "]" << endl;
}
class Solution {
public:
multiset<double> arr;
void insert(double x) { arr.insert(x); }
void delete_(double x) { arr.erase(arr.find(x)); }
double getMedian() {
int n = arr.size();
double a = *next(arr.begin(), n / 2 - 1);
double b = *next(arr.begin(), n / 2);
if (n & 1) return b;
return (a + b) * 0.5;
}
vector<double> medianSlidingWindow(vector<int>& nums, int k) {
vector<double> ans;
arr.clear();
for (int i = 0; i < k; i++) insert(nums[i]);
for (int i = k, j = 0; i < nums.size(); i++, j++) {
ans.push_back(getMedian());
delete_(nums[j]);
insert(nums[i]);
}
ans.push_back(getMedian());
return ans;
}
};
int main() {
Solution ob;
vector<int> v = {1, 3, -1, -3, 5, 3, 6, 8};
print_vector(ob.medianSlidingWindow(v, 3));
}
การวิเคราะห์ความซับซ้อน
- เวลา: O(n log k) — แต่ละการแทรก/ลบ/หามัธยฐาน ใช้ O(log k)
- พื้นที่: O(k) — เก็บองค์ประกอบในหน้าต่าง
การทดสอบ
Input: {1,3,-1,-3,5,3,6,8}, k=3
Output: [1, -1, -1, 3, 5, 6]