480. Sliding Window Median


Median is the middle value in an ordered integer list. If the size of the list is even, there is no middle value. So the median is the mean of the two middle value.

Examples:

[2,3,4] , the median is 3

[2,3], the median is (2 + 3) / 2 = 2.5

Given an array nums, there is a sliding window of size k which is moving from the very left of the array to the very right. You can only see the k numbers in the window. Each time the sliding window moves right by one position. Your job is to output the median array for each window in the original array.

For example,

Given nums = [1,3,-1,-3,5,3,6,7], and k = 3.

Window position                Median
---------------               -----
[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
Therefore, return the median sliding window as [1,-1,-1,3,5,6].

Note:

  1. You may assume k is always valid, ie: k is always smaller than input array’s size for non-empty array.

花花:https://zxi.mytechroad.com/blog/difficulty/hard/leetcode-480-sliding-window-median/
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

方法1: multiset (priority_queue)

grandyang: http://www.cnblogs.com/grandyang/p/6620334.html
discussion: https://leetcode.com/problems/sliding-window-median/discuss/96340/O(n-log-k)-C%2B%2B-using-multiset-and-updating-middle-iterator

思路:

multiset是不支持直接O(1)提取中位数的。那么解决的办法就是maintain一个pointer,每次插入删除时和当前的median做对比,如果插入的是左边,median一定会被拉低,如果是右边,median被拉高。相应调整median iterator的位置。而对于滑出了窗口的数,我们要用erase删除,但是必须用lower_bound来定位这个元素,因为multiset里面可能会存在重复的该元素,不能一次都删掉。lower_bound会指向multiset中第一个大于等于目标值的数字。

Complexity

Time complexity: O(n log k)
Space complexity: O(logk)

class Solution {
public:
    vector<double> medianSlidingWindow(vector<int>& nums, int k) {
        vector<double> result;
        // initialize the window
        multiset<int> window(nums.begin(), nums.begin() + k);
        // iterator to the median
        auto mid = next(window.begin(), k / 2); //偶数情况下取的是右中位
        for (int i = k; ; i++) {
            
            result.push_back(((double)(*mid) + *prev(mid, (1 - k % 2)) )* 0.5);
            // if hit the end, return
            if (i == nums.size()) return result;
           
            // insert
            window.insert(nums[i]);
            
            // 如果要被插入左半 mid--
            if (nums[i] < *mid) {
                mid--;
            }
            // 如果要被删除的在左半mid++
            if (nums[i - k] <= *mid) {
                mid++;
            }
            // 考虑几种情况:
            // 1. 插左删左,插右删右,mid不变
            // 2. 插左删右,mid--
            // 3. 插右删左,mid++
            window.erase(window.lower_bound(nums[i - k]));
            
        }
    }
};

方法2: insertion sort

huahua: https://zxi.mytechroad.com/blog/difficulty/hard/leetcode-480-sliding-window-median/

// Author: Huahua
// Running time: 99 ms
class Solution {
public:
  vector<double> medianSlidingWindow(vector<int>& nums, int k) {    
    vector<double> ans;
    if (k == 0) return ans;
    vector<int> window(nums.begin(), nums.begin() + k - 1);
    std::sort(window.begin(), window.end());
    for (int i = k - 1; i < nums.size(); ++i) {
      window.push_back(nums[i]);
      auto it = prev(window.end(), 1);
      auto const insertion_point = 
              std::upper_bound(window.begin(), it, *it);      
      std::rotate(insertion_point, it, it + 1);          
      ans.push_back((static_cast<double>(window[k / 2]) + window[(k - 1) / 2]) / 2);
      window.erase(std::find(window.begin(), window.end(), nums[i - k + 1]));      
    }
    return ans;
  }
};
The Sliding Window Protocol is a flow control protocol used in computer networks to ensure reliable and efficient data transfer between two nodes. It is implemented using a sliding window, which is a buffer of fixed size that stores the data packets to be transmitted and received. The sliding window protocol is a stop-and-wait protocol, which means that the sender sends a packet and waits for an acknowledgement from the receiver before sending the next packet. The receiver sends an acknowledgement packet to the sender indicating that it has received the packet successfully. The sliding window protocol has two parameters: the window size and the sequence number. The window size represents the number of packets that can be sent without waiting for an acknowledgement. The sequence number is a unique identifier assigned to each packet to ensure that the packets are delivered in the correct order. Here is a sample program in Python that implements the Sliding Window Protocol: ```python import socket import time # Define the window size and sequence number WINDOW_SIZE = 4 SEQ_NUM_SIZE = 4 # Define the packet format PACKET_FORMAT = "!I1024s" # Define the server address and port SERVER_ADDRESS = "localhost" SERVER_PORT = 12345 # Define the data to be sent DATA = "Hello, world!".encode("utf-8") # Create the socket and connect to the server client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) client_socket.connect((SERVER_ADDRESS, SERVER_PORT)) # Initialize the sequence number and window seq_num = 0 window_start = 0 window_end = WINDOW_SIZE # Send the packets while window_start < len(DATA): # Send the packets in the current window for i in range(window_start, window_end): # Create the packet packet_data = DATA[i:i+1024] packet_seq_num = seq_num.to_bytes(SEQ_NUM_SIZE, byteorder="big") packet = struct.pack(PACKET_FORMAT, packet_seq_num, packet_data) # Send the packet client_socket.send(packet) # Increment the sequence number seq_num += 1 # Wait for the acknowledgements ack_received = False while not ack_received: # Set the timeout client_socket.settimeout(1) # Wait for the acknowledgement try: ack = client_socket.recv(1024) # Check if the acknowledgement is valid if ack: ack_seq_num = int.from_bytes(ack, byteorder="big") if ack_seq_num == window_start: ack_received = True # Update the window window_start += 1 window_end += 1 except socket.timeout: # If the timeout occurs, resend the packets in the current window for i in range(window_start, window_end): packet_data = DATA[i:i+1024] packet_seq_num = (seq_num - WINDOW_SIZE + i).to_bytes(SEQ_NUM_SIZE, byteorder="big") packet = struct.pack(PACKET_FORMAT, packet_seq_num, packet_data) client_socket.send(packet) # Wait for a short period of time before sending the next window time.sleep(0.1) # Close the socket client_socket.close() ``` In this program, the client sends the data in packets of size 1024 bytes and waits for an acknowledgement from the server before sending the next packet. The program uses a sliding window of size 4, which means that the client can send up to 4 packets at a time without waiting for an acknowledgement. The program also implements a timeout mechanism to handle lost packets. If the client does not receive an acknowledgement within 1 second, it resends the packets in the current window. Overall, the Sliding Window Protocol provides reliable and efficient data transfer in computer networks by using a sliding window to control the flow of data between two nodes.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值