【Lintcode】362. Sliding Window Maximum

题目地址:

https://www.lintcode.com/problem/sliding-window-maximum/description

给定一个数组,再给定一个正整数 k k k,求数组所有长度为 k k k的滑动窗口最大数字。

思路是单调队列。维护一个单调下降的双端队列(从队头到队尾严格下降),每遇到一个数 x x x的时候,先将队尾小于等于 x x x的数poll出来,再将队头出了滑动窗口的数也poll出来,再把 x x x加入队列。这样队头维护的就是滑动窗口的最大值。注意,由于要将队头出了滑动窗口的数也poll出来,如果队列存的是数组中的数字本身的话,会很不方便,所以队列存的实际上是数的下标。代码如下:

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.List;

public class Solution {
    /**
     * @param nums: A list of integers.
     * @param k: An integer
     * @return: The maximum number inside the window at each moving.
     */
    public List<Integer> maxSlidingWindow(int[] nums, int k) {
        // write your code here
        List<Integer> res = new ArrayList<>();
        Deque<Integer> deque = new ArrayDeque<>();

		// 我们计算以nums[i]为最后元素的滑动窗口中的最大数
        for (int i = 0; i < nums.length; i++) {
        	// 将队尾小于等于nums[i]的下标出队
            while (!deque.isEmpty() && nums[i] >= nums[deque.peekLast()]) {
                deque.pollLast();
            }
            // 如果队首下标出了窗口,也出队
            if (!deque.isEmpty() && deque.peekFirst() <= i - k) {
                deque.pollFirst();
            }
            // 最后再将当前数字下标入队
            deque.offerLast(i);
            
            if (i >= k - 1) {
            	// 队头存的是滑动窗口最大数的下标,加入最终结果res
                res.add(nums[deque.peekFirst()]);
            }
        }
        
        return res;
    }
}

时间复杂度 O ( n ) O(n) O(n),空间 O ( k ) O(k) O(k)

算法正确性证明:
首先证明队列中数字保持单调。对 i i i进行数学归纳法。当 i = 0 i=0 i=0时循环结束时队列里只有一个数,显然成立;假设对 i = k i=k i=k时成立,当 i = k + 1 i=k+1 i=k+1时,由于队列已经单调,所以小于 A [ i ] A[i] A[i]的数都集中在队尾,while循环中队尾大于 A [ i ] A[i] A[i]的数(下标)都会出队,所以队列维持单调不变。

接下来证明,对于每个 i i i,队列里从队头到队尾存放的是从 A [ i − k + 1 , . . . , i ] A[i-k+1,...,i] A[ik+1,...,i]的数中,最大数在队头,最大数右边的数中的最大数,在队列第二位,此数右边的数中的最大数,在队列第三位,以此类推。也可以用数学归纳法来证明。由于每当新来一个数,都会把队尾不超过它的数PK下来,并且把出了窗口的数也出队,所以这一条结论显然成立。那么队头就维护了窗口最大值。所以算法正确。

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、付费专栏及课程。

余额充值