每日练习——leetcode1047和239

目录

1047. 删除字符串中的所有相邻重复项

题目描述

解题思路

代码实现

239. 滑动窗口最大值

题目描述

解题思路

代码实现


1047. 删除字符串中的所有相邻重复项

题目描述

给出由小写字母组成的字符串 S重复项删除操作会选择两个相邻且相同的字母,并删除它们。

在 S 上反复执行重复项删除操作,直到无法继续删除。

在完成所有重复项删除操作后返回最终的字符串。答案保证唯一。

示例:

输入:"abbaca"
输出:"ca"
解释:
例如,在 "abbaca" 中,我们可以删除 "bb" 由于两字母相邻且相同,这是此时唯一可以执行删除操作的重复项。之后我们得到字符串 "aaca",其中又只有 "aa" 可以执行重复项删除操作,所以最后的字符串为 "ca"。

提示:

  1. 1 <= S.length <= 20000
  2. S 仅由小写英文字母组成。

解题思路

  1. 获取字符串长度并初始化栈
    • 首先,使用strlen函数获取输入字符串s的长度,并存储在变量len中。
    • 接着,为栈分配足够的内存空间(len + 1),其中额外的1个位置是为了存放字符串的结束符\0
    • 定义了一个变量stackTop来追踪栈顶的位置,初始时栈为空,所以stackTop设为0。
  2. 遍历字符串并处理相邻重复字符
    • 使用一个for循环来遍历输入字符串s中的每个字符。
    • 对于每个字符s[i],检查它是否与当前栈顶元素stack[stackTop - 1]相同。
    • 如果相同,说明出现了相邻的重复字符,将栈顶指针stackTop减1,以移除栈顶的重复字符。
    • 如果不同,或者栈为空(即stackTop为0),则将当前字符s[i]压入栈中,并递增栈顶指针stackTop
  3. 添加字符串结束符并返回结果
    • 遍历完整个字符串后,在栈中最后一个有效字符的位置(即stack[stackTop - 1]之后,即stack[stackTop])添加一个字符串结束符\0,这样stack就形成了一个合法的C字符串。
    • 最后,返回栈的地址,即处理后的字符串。

代码实现

char* removeDuplicates(char* s) {
    int len = strlen(s);
    char* stack =(char *)malloc(sizeof(char)*(len + 1));
    int stackTop = 0;
    for (int i = 0; i < len; i++) {
        if (stackTop > 0 && stack[stackTop - 1] == s[i]) {
            stackTop--;
        } else {
            stack[stackTop++] = s[i];
        }
    }
    stack[stackTop] = '\0';
    return stack;
}

239. 滑动窗口最大值

题目描述

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

返回 滑动窗口中的最大值 

示例 1:

输入:nums = [1,3,-1,-3,5,3,6,7], k = 3
输出:[3,3,5,5,6,7]
解释:
滑动窗口的位置                最大值
---------------               -----
[1  3  -1] -3  5  3  6  7       3
 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       5
 1  3  -1  -3 [5  3  6] 7       6
 1  3  -1  -3  5 [3  6  7]      7

示例 2:

输入:nums = [1], k = 1
输出:[1]

提示:

  • 1 <= nums.length <= 105
  • -104 <= nums[i] <= 104
  • 1 <= k <= nums.length

解题思路

  1. 定义变量
    • n:数组 nums 的长度。
    • queue:一个数组,用于模拟队列的操作,存储窗口内可能的最大值。
    • front 和 rear:分别表示队列的队首和队尾索引。
    • left 和 right:分别表示当前滑动窗口的左边界和右边界。
  2. 窗口右移
    • 遍历数组 nums,从 right = 0 开始,直到 right 达到数组末尾。
  3. 维护队列的单调性
    • 在每次窗口右移时,检查队列的队尾元素是否小于新元素 nums[right]。如果是,则不断从队尾弹出元素,直到队列为空或找到不小于 nums[right] 的元素。
    • 然后,将新元素 nums[right] 入队。
  4. 处理窗口大小大于 k 的情况
    • 当窗口的大小(right - left + 1)大于 k 时,说明窗口的左边界需要向右移动。
    • 如果队列的队首元素(即当前窗口的最大值)与 nums[left] 相等,则将队首元素出队,因为该元素已经不在窗口内了。
    • 否则,将 nums[left] 更新为队首元素,即当前窗口的最大值。
    • 然后,左边界 left 向右移动一位。
  5. 返回结果
    • 遍历完成后,滑动窗口已经遍历了整个数组 nums
    • nums 数组中的每个位置 left(即每个窗口的左边界)都存储了对应窗口的最大值。
    • 函数返回修改后的 nums 数组,并通过 returnSize 返回窗口的个数,即 n - k + 1

代码实现

/**
 * Note: The returned array must be malloced, assume caller calls free().
 */
int* maxSlidingWindow(int* nums, int numsSize, int k, int* returnSize) {
	int n = numsSize; // n 为数组 nums 的长度  
    int queue[n];     // 队列,用于存储当前窗口内的元素索引  
    int front = 0, rear = -1; // 队首和队尾索引,分别指向队列的第一个和最后一个元素  
    int left = 0, right = 0;  // 窗口的左边界和右边界索引  
  
    // 当右边界没有达到数组末尾时,继续移动窗口  
    while (right < n) {  
        // 如果队列不为空且当前元素大于队列尾部的元素,则将队列尾部的元素出队  
        // 这样可以保证队列是单调递减的,即队首元素是当前窗口的最大值  
        while (rear >= front && nums[right] > nums[queue[rear]]) {  
            rear--;  
        }  
        // 将当前元素的索引入队  
        queue[++rear] = right;  
        // 右边界向右移动一位  
        right++;  
  
        // 当窗口大小大于 k 时,左边界需要向右移动  
        if (left + k <= right) {  
            // 如果队列的队首元素(即当前窗口的最大值)对应的索引等于左边界的索引  
            // 则说明这个最大值已经不在窗口内了,将其从队列中出队  
            if (queue[front] == left) {  
                front++;  
            }  
            // 将当前窗口的最大值(即队列的队首元素对应的值)存入原数组对应的位置  
            nums[left] = nums[queue[front]];  
            // 左边界向右移动一位  
            left++;  
        }  
    }  
  
    // 设置返回数组的大小为窗口的个数,即 n - k + 1  
    *returnSize = n - k + 1;  
  
    // 返回修改后的原数组,它现在包含了每个窗口的最大值  
    return nums;  
}

  • 28
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值