代码随想录算法训练营22期--Day 2

代码随想录算法训练营第二天| 977.有序数组的平方、209.长度最小的子数组 、59.螺旋矩阵 II

1. 977.有序数组的平方

Leetcode题目链接

题目:给定一个按非递减顺序排序的整数数组 nums,返回每个数字的平方组成的新数组,要求也按非递减顺序排序。

思路1:最直接想到的是首先对数组的每个数据平方,然后重新排序,这样带来的时间复杂度主要取决于排序算法的复杂度。具体代码如下:

int* sortedSquares(int* nums, int numsSize, int* returnSize){
    void sort(int array[],int num);
    *returnSize = numsSize;
    int *p;
    p = (int *)calloc(sizeof(int) , 10000);
    for(int i = 0; i < numsSize; i++) {
        p[i] = nums[i] * nums[i];
    }
    sort(p,numsSize);
    return p;
}

void sort(int array[],int num)
{
    int t;
    for(int i = 0; i < num - 1; i++)
        for(int j = 0; j < num - i - 1; j++ ) {
            if(array[j] > array[j+1]) {
                t = array[j];
                array[j] = array[j+1];
                array[j+1] = t;
            }
        }
}
  • 时间复杂度:O(nlog n)

思路2:另一种方法是采用双指针法,由于nums中的元素是按非递减顺序排序的,因此元素平方后,最大值一定在数组两边的位置,最小值在数组中间的位置,因此定义两个指针分别指向数组两边,然后逐步向中间移动,每次将两个指针指向的元素平方值更大的结果放在新数组中,并更新相应的指针。代码如下所示:

int* sortedSquares(int* nums, int numsSize, int* returnSize){
    int *p, k, left, right;
    p = (int *)calloc(sizeof(int),10000);
    *returnSize = numsSize;
    for(left = 0, right = numsSize - 1, k = numsSize - 1; left <= right;) {
        if(nums[left] * nums[left] > nums[right] * nums[right]) {
            p[k--] = nums[left] * nums[left];
            left++;
        }
        else {
            p[k--] = nums[right] * nums[right];
            right--;
        }
    }
    return p;
}
  • 时间复杂度:O(n)

2. 209.长度最小的子数组

Leetcode题目链接

题目:给定一个含有 n 个正整数的数组和一个正整数 s,找出该数组中满足其和 ≥ s 的长度最小的连续子数组,并返回其长度。如果不存在符合条件的子数组,返回 0。

思路1:直接的想法是采用两个for循环暴力求解,不断地寻找符合条件的子序列,具体代码如下所示:

int minSubArrayLen(int target, int* nums, int numsSize){
    int len_min = numsSize+1, sum, flag;
    for (int i = 0; i < numsSize; i++) {
        int len = 0;
        sum = 0;
        flag = 0;
        for (int j = i; j < numsSize; j++) {
            len++;
            sum += nums[j];
            if (sum >= target){
                flag = 1;
                break;
            }
        }
        if(flag)
            len_min = len_min > len ? len : len_min;
    }
    if(len_min>numsSize)
        return 0 ;
    else
        return len_min;
}
  • 时间复杂度:O(n^2)
  • 空间复杂度:O(1)

注意:Leetcode上这道题采用暴力解法会超时。

思路2:另一种方法是滑动窗口法(双指针法的一种),其采用一个for循环完成了之前两个for循环完成的工作。重点是明确for循环里循环索引表示的应该是滑动窗口的终止位置(若为起始位置,则与两个for循环的逻辑类似)。起始位置的移动则取决于当前窗口的值的大小,若当前窗口的值大于s,窗口就要向前移动(也就是该缩小了)。代码如下:

int minSubArrayLen(int target, int* nums, int numsSize){
    int left = 0, sum = 0, flag = 0, len = numsSize;
    for(int i = 0; i < numsSize; i++) {
        sum += nums[i];
        while(sum >= target) {
            len = len < i - left + 1 ? len : i - left + 1;
            sum -= nums[left++];
            flag = 1;
        }
    }
    if(flag)
        return len;
    else
        return 0;
}
  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

3. 59.螺旋矩阵 II

Leetcode题目链接

题目:(模拟题)给定一个正整数 n,生成一个包含 1 到 n^2 所有元素,且元素按顺时针顺序螺旋排列的正方形矩阵。

思路:重点是遵循循环不变量原则,处理边界条件时要一直遵循左闭右开或左开右闭的准则。代码如下:

int** generateMatrix(int n, int* returnSize, int** returnColumnSizes){
    *returnSize = n;
    *returnColumnSizes = (int*)malloc(sizeof(int) * n);
    //初始化返回结果数组ans
    int** ans = (int**)malloc(sizeof(int*) * n);
    int i;
    for(i = 0; i < n; i++) {
        ans[i] = (int*)malloc(sizeof(int) * n);
        (*returnColumnSizes)[i] = n;
    }

    int startx = 0, starty = 0, offset = 1, loop = n/2, count = 1;
    while(loop) {
        int i = startx, j = starty;
        for(; j < n - offset; j++)
            ans[startx][j] = count++;
        for(; i < n - offset; i++)
            ans[i][j] = count++;
        for(; j > starty; j--)
            ans[i][j] = count++;
        for(; i > startx; i--)
            ans[i][j] = count++;
        startx++;
        starty++;
        offset++;
        loop--;
    }
    if(n%2)
        ans[startx][starty] = count;
    return ans;
}
  • 时间复杂度:O(n^2)
  • 空间复杂度:O(1)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值