480. 滑动窗口中位数 ( 有序数组+滑动窗口)

 

难度困难

中位数是有序序列最中间的那个数。如果序列的长度是偶数,则没有最中间的数;此时中位数是最中间的两个数的平均数。

例如:

  • [2,3,4],中位数是 3
  • [2,3],中位数是 (2 + 3) / 2 = 2.5

给你一个数组 nums,有一个长度为 k 的窗口从最左端滑动到最右端。窗口中有 k 个数,每次窗口向右移动 1 位。你的任务是找出每次窗口移动后得到的新窗口中元素的中位数,并输出由它们组成的数组。

 

示例:

给出 nums = [1,3,-1,-3,5,3,6,7],以及 k = 3。

窗口位置                      中位数
---------------               -----
[1  3  -1] -3  5  3  6  7       1
 1 [3  -1  -3] 5  3  6  7      -1
 1  3 [-1  -3  5] 3  6  7      -1
 1  3  -1 [-3  5  3] 6  7       3
 1  3  -1  -3 [5  3  6] 7       5
 1  3  -1  -3  5 [3  6  7]      6

 因此,返回该滑动窗口的中位数数组 [1,-1,-1,3,5,6]

 

 

from sortedcontainers import SortedList

class Solution:
    def medianSlidingWindow(self, nums: List[int], k: int) -> List[float]:
   
     
        def get_median(window):
            n = len(window)
            if n % 2 == 1:
                return window[n // 2]
            else:
                return (window[n // 2 - 1] + window[n // 2]) / 2
        
        st = SortedList()
        ans = []        
        for i in range(len(nums)):
            #这个条件用于确保我们已经处理了至少 k 个元素后,窗口才开始滑动。
            if i >= k:
                st.remove(nums[i - k])
            st.add(nums[i])
            #只有当窗口的大小达到了 k 之后,我们才能开始计算中位数
            if i >= k - 1:
                median = get_median(st)
                ans.append(median)
        
        return ans

 

 

 

 

 

 

 

class Solution {
public:
    vector<double> medianSlidingWindow(vector<int>& nums, int k) {
        vector<double> res;
        for(int i = 0; i <= nums.size()-k;i++) {
            
            vector<long> temp(nums.begin()+i,nums.begin()+i+k); //开区间
            sort(temp.begin(),temp.end());
            double a = k%2!=0?temp[k/2]: double(temp[k/2]+temp[k/2-1])/2.0;
            res.emplace_back(a);
        }
        return res;
    }
};

 

 

class Solution {
public:
  vector<double> medianSlidingWindow(vector<int>& nums, int k) {
        vector<double> ret;
        multiset<int> window(nums.begin(), nums.begin() + k); // 初始化set,将前k个数存入set
        auto mid = std::next(window.begin(), k / 2); // 基数:获取中数的位置,偶数:获取中数计数参数的后一个数的位置
        for (int idx = k;idx < nums.size() ; idx++) {
            // 1、计数每组窗口中数组的中数,并存入ret中
            auto midValue = ((double)(*mid) + (double)*next(mid, k % 2 - 1)) / 2;
            ret.push_back(midValue);
            
            // 遍历完了,退出
            if (idx == nums.size()) {
                break;
            }
            // 窗口后移
            window.insert(nums[idx]);
            if (nums[idx] < *mid)
                mid--;                  // same as mid = prev(mid)

            // Remove outgoing element
            if (nums[idx - k] <= *mid)
                mid++;                  // same as mid = next(mid)

            // 删除一个元素
            window.erase(window.lower_bound(nums[idx-k]));
        }

        return ret;
    }
};

 

 

 

posted @ 2022-08-22 22:46  乐乐章  阅读(21)  评论(0编辑  收藏  举报