每日练习——leetcode209和LCR 024

本文介绍了如何使用双指针和滑动窗口算法解决“长度最小的子数组”问题,以及两种方法——双指针迭代和递归——来实现链表反转。通过实例和代码展示了这两种技术在实际问题中的应用。
摘要由CSDN通过智能技术生成

目录

209. 长度最小的子数组

题目

解题思路

算法:双指针,滑动窗口

代码实现

LCR 024. 反转链表

题目

解题思路

法1:双指针、迭代

法2:递归

 代码实现


209. 长度最小的子数组

题目

给定一个含有 n 个正整数的数组和一个正整数 target 。

找出该数组中满足其总和大于等于 target 的长度最小的 连续子数组 [numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度如果不存在符合条件的子数组,返回 0 

示例 1:

输入:target = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3]是该条件下的长度最小的子数组。

示例 2:

输入:target = 4, nums = [1,4,4]
输出:1

示例 3:

输入:target = 11, nums = [1,1,1,1,1,1,1,1]
输出:0

提示:

  • 1 <= target <= 109
  • 1 <= nums.length <= 105
  • 1 <= nums[i] <= 105

进阶:

  • 如果你已经实现 O(n) 时间复杂度的解法, 请尝试设计一个 O(n log(n)) 时间复杂度的解法。

解题思路

算法:双指针,滑动窗口

1.初始化变量

定义两个指针 i  j ,用来确定字数组的起始和结束位置。定义sum用来计算当前子数组的和,len用来存储当前子数组的长度,result 用来存储最小的满足条件的子数组长度,初始化为一个很大的值(INT_MAX),这样找到的任何的有效长度都会小于这个初始值。

2.遍历数组

然后使用一个循环遍历数组,在每次循环过程中,将当前元素 nums[j] ,添加到 sum 中。

3.检查子数组和

如果 sum 大于或等于 target ,则进入内部循环,在内部循环中,首先计算当前子数组的长度len(即j-i+1)。然后,更新 result 为 result  len 中的较小值。接着,从 sum 中减去子数组起始位置的元素 nums[i] ,并将 i 向右移动一个位置(即缩小子数组的范围,看是否找到更小的满足条件的子数组)。

4.返回结果

如果在遍历整个数组后没有找到满足条件的子数组(即 result 仍然是 INT_MAX ),则返回 0 。否则,返回 result (即最小的满足条件的子数组的长度)

【补充】

  • INT_MAX为 2^31-1 ,即 2147483647 ;
  • INT_MIN为 -2^31 , 即 2147483648 ;
  • 在使用INT_MAX和INT_MIN时,需要 #include<limits.h>;

代码实现

int minSubArrayLen(int target, int* nums, int numsSize) {
    int i = 0, j, sum = 0, len = 0, result = INT_MAX;
    // i 和 j 是双指针,用于确定子数组的起始和结束位置
    // sum 用于计算当前子数组的和
    // len 用于存储当前子数组的长度
    // result
    // 用于存储最小的满足条件的子数组长度,初始化为一个很大的值(INT_MAX)

    {
        for (j = 0; j < numsSize; j++) {
            // 遍历数组,j 是当前考虑的元素的索引
            sum += nums[j]; // 将当前元素加入sum中

            while (sum >= target) {
                // 当sum大于等于target时,进入循环
                len = j - i + 1; // 计算当前子数组的长度
                // 更新result为当前result和len中的较小值
                result = result < len ? result : len;

                sum -= nums[i]; // 从sum中减去子数组起始位置的元素
                i++; // 将子数组的起始位置向右移动一个位置
            }
        }

        // 如果在遍历过程中没有找到满足条件的子数组,则result仍然为INT_MAX
        // 因此,如果result等于INT_MAX,则返回0;否则返回result
        return result == INT_MAX ? 0 : result;
    }
}

LCR 024. 反转链表

题目

给定单链表的头节点 head ,请反转链表,并返回反转后的链表的头节点。

示例 1:

输入:head = [1,2,3,4,5]
输出:[5,4,3,2,1]

示例 2:

输入:head = [1,2]
输出:[2,1]

示例 3:

输入:head = []
输出:[]

提示:

  • 链表中节点的数目范围是 [0, 5000]
  • -5000 <= Node.val <= 5000

进阶:链表可以选用迭代或递归方式完成反转。你能否用两种方法解决这道题?

解题思路

法1:双指针、迭代

1.初始化指针

定义两个指针 current pre ,分别用来指向链表的头结点 head current 的前一个节点,初始化为 NULL

2.遍历链表

使用一个 while 循环遍历链表,直到 current NULL

3.改变节点指针方向

在每次循环中首先定义一个临时指针 temp ,用来指向 current 的下一个节点(因为需要移动current)。然后,将 current next 指针指向前一个节点 pre ,这样就反转了 current 节点的指向。

4.移动指针

pre 更新为 current ,因为想让 pre 指向刚刚反转过的节点。将 current 更新为 temp ,因为想继续处理链表的下一个节点。

5.返回反转后的头结点

current NULL 时,循环结束,此时 pre 将指向反转后链表的最后一个节点,也就是新链表的头结点。函数返回 pre ,即反转后的链表头结点。

在这个过程中,链表中的每个节点得到 next 指针都被反转,从而实现了链表的反转。

法2:递归

1.定义递归函数reverse

改递归函数接受两个参数:current(当前节点)和 pre(前一个节点),目的是将当前节点 current的 next 指针指向 pre ,然后递归处理剩余的链表。

2.递归处理

如果 current NULL ,说明已经到达链表的末尾,返回 pre 作为新链表头结点。否则,将 current next 指针保存到一个临时变量 temp 中,然后将 current next 指针指向 pre。递归调用 reverse 函数,传入 temp current 作为参数,继续处理剩余的链表。

3.调用递归函数reverse

reverseList 函数中,调用 reverse 函数,将头结点 head 和一个空指针 NULL 作为参数传递给reverse,这样,当递归到链表的末尾时,空指针将作为新链表的头结点的前一个节点,从而实现链表的反转。

 代码实现

//迭代方式
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */

struct ListNode* reverseList(struct ListNode* head) {
    struct ListNode* current = head;
    struct ListNode* pre = NULL;
    while (current) {
        struct ListNode* temp = current->next;
        current->next=pre;
        pre=current;
        current=temp;
    }
    return pre;
}
//递归方式
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */

struct ListNode* reverse(struct ListNode* current, struct ListNode* pre) {
    if (current == NULL) {
        return pre;
    }
    struct ListNode* temp = current->next;
    current->next = pre;
    return reverse(temp, current);
}
struct ListNode* reverseList(struct ListNode* head) {
     return reverse(head, NULL); 
     }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值