力扣239题(队列、栈、单调队列,难)

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/sliding-window-maximum
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

239.给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。返回滑动窗口中的最大值。

  1. 看到题目觉得滑动窗口应该由一个队列来完成,因为滑动窗口很符合队列先进先出的一个原则。但是想来想去想不出应该如何完成找到滑动窗口中的最大值,直接暴力找到滑动窗口的最大值时间复杂度太高了。尝试了一下,果然在短的测试用例上能通过,但是遇到长的测试用例,就超出时间限制了。
int findMaxinWindow(int *arr, int size) {
    int max = arr[0];
    for (int i = 0; i < size; i++) {
        if (max < arr[i])
            max = arr[i];
    }
    return max;
}

/**
 * Note: The returned array must be malloced, assume caller calls free().
 */
int* maxSlidingWindow(int* nums, int numsSize, int k, int* returnSize){
    *returnSize = numsSize - k + 1;
    int *res = malloc(sizeof(int) * (numsSize - k + 1));
    int *queue = malloc(sizeof(int) * k);
    int head = -1;
    int rear = -1;
    int j = 0;
    for (int i = 0; i < numsSize; i++) {
        if (i < k) {
            rear = (rear + 1) % k;
            queue[rear] = nums[i];
            if (head == -1)
                head = 0;
            if (i + 1 == k)
                res[j++] = findMaxinWindow(queue,k);
        }  else {
            head = (head + 1) % k;
            rear = (rear + 1) % k;
            queue[rear] = nums[i];
            res[j++] = findMaxinWindow(queue, k);
        }
    }
    return res;
}
  1. 这种用堆来解题的题解看不懂,先留着之后再学习吧。
void swap(int** a, int** b) {
    int* tmp = *a;
    *a = *b, *b = tmp;
}

int cmp(int* a, int* b) {
    return a[0] == b[0] ? a[1] - b[1] : a[0] - b[0];
}

struct Heap {
    int** heap;
    int size;
    int capacity;
};

void init(struct Heap* obj, int capacity) {
    obj->size = 0;
    obj->heap = NULL;
    obj->capacity = capacity;
    obj->heap = malloc(sizeof(int*) * (obj->capacity + 1));
    for (int i = 1; i <= obj->capacity; i++) {
        obj->heap[i] = malloc(sizeof(int) * 2);
    }
}

void setFree(struct Heap* obj) {
    for (int i = 1; i <= obj->capacity; i++) {
        free(obj->heap[i]);
    }
    free(obj->heap);
    free(obj);
}

void push(struct Heap* obj, int num0, int num1) {
    int sub1 = ++(obj->size), sub2 = sub1 >> 1;
    (obj->heap[sub1])[0] = num0, (obj->heap[sub1])[1] = num1;
    while (sub2 > 0 && cmp(obj->heap[sub2], obj->heap[sub1]) < 0) {
        swap(&(obj->heap[sub1]), &(obj->heap[sub2]));
        sub1 = sub2, sub2 = sub1 >> 1;
    }
}

void pop(struct Heap* obj) {
    int sub = 1;
    swap(&(obj->heap[sub]), &(obj->heap[(obj->size)--]));
    while (sub <= obj->size) {
        int sub1 = sub << 1, sub2 = sub << 1 | 1;
        int maxSub = sub;
        if (sub1 <= obj->size && cmp(obj->heap[maxSub], obj->heap[sub1]) < 0) {
            maxSub = sub1;
        }
        if (sub2 <= obj->size && cmp(obj->heap[maxSub], obj->heap[sub2]) < 0) {
            maxSub = sub2;
        }
        if (sub == maxSub) {
            break;
        }
        swap(&(obj->heap[sub]), &(obj->heap[maxSub]));
        sub = maxSub;
    }
}

int* top(struct Heap* obj) {
    return obj->heap[1];
}

int* maxSlidingWindow(int* nums, int numsSize, int k, int* returnSize) {
    struct Heap* q = malloc(sizeof(struct Heap));
    init(q, numsSize);
    for (int i = 0; i < k; i++) {
        push(q, nums[i], i);
    }
    int* ans = malloc(sizeof(int) * (numsSize - k + 1));
    *returnSize = 0;
    ans[(*returnSize)++] = top(q)[0];

    for (int i = k; i < numsSize; ++i) {
        push(q, nums[i], i);
        while (top(q)[1] <= i - k) {
            pop(q);
        }
        ans[(*returnSize)++] = top(q)[0];
    }
    setFree(q);
    return ans;
}

作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/sliding-window-maximum/solution/hua-dong-chuang-kou-zui-da-zhi-by-leetco-ki6m/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  1. 还有一种题解是用一种叫单调队列的数据结构来解题的题解。具体请看leetcode官方题解
int* maxSlidingWindow(int* nums, int numsSize, int k, int* returnSize) {
    int q[numsSize];
    int left = 0, right = 0;
    //让第一个滑动窗口中的元素按照规则存储到单调队列中,也就是只存储第一个滑动窗口中满足严格单调递减的部分
    for (int i = 0; i < k; ++i) {
        while (left < right && nums[i] >= nums[q[right - 1]]) {
            right--;
        }
        q[right++] = i;
    }
    *returnSize = 0;
    //单调队列中存的第一个元素就是当前滑动窗口中最大的元素
    int* ans = malloc(sizeof(int) * (numsSize - k + 1));
    ans[(*returnSize)++] = nums[q[left]];
    //开始移动滑动窗口,同时要继续维护单调队列
    for (int i = k; i < numsSize; ++i) {
        while (left < right && nums[i] >= nums[q[right - 1]]) {
            right--;
        }
        q[right++] = i;
        //为了防止单调队列中的元素滑动窗口外的元素,还要从队头不断弹出不属于当前滑动窗口的元素
        while (q[left] <= i - k) {
            left++;
        }
        ans[(*returnSize)++] = nums[q[left]];
    }
    return ans;
}

作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/sliding-window-maximum/solution/hua-dong-chuang-kou-zui-da-zhi-by-leetco-ki6m/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

说实话这个题解看了挺久,有点没反应过来一开始。大概看懂这题解后,觉得为什么单调队列中要存下标而不直接存元素呢,感觉那样更直观,于是自己鼓捣着把下标改成了元素,后面就发现出了问题,在弹出单调队列中不属于当前滑动窗口的元素这一步不知道该怎么做了,所以看问题还是需要更加全面一点,这个题目算是长见识了,但目前害属于脑子会了手不会的情况,有空一定得回来重新做一遍。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值