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

977.有序数组的平方 

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

暴力排序

每个数平方后排序

这里有两步操作--平方操作和冒泡排序,平方操作的时间复杂度为 O(n),冒泡排序的时间复杂度为 O(n^2),整个函数的时间复杂度为 O(n^2)

(冒泡排序需要进行 numsSize - 1 轮比较和交换操作,每轮操作需要比较 numsSize - i - 1 对相邻元素,并可能进行交换。在最坏情况下,需要进行 n-1+n-2+...+1 = (n-1)*n/2 次比较和交换。)

/**
 * Note: The returned array must be malloced, assume caller calls free().
 */
int* sortedSquares(int* nums, int numsSize, int* returnSize) {
    int* result = (int*)malloc(numsSize * sizeof(int));  // 分配结果数组的内存

    for (int i = 0; i < numsSize; i++) {
        result[i] = nums[i] * nums[i];
    }

    // 使用冒泡排序对平方后的数组进行非递减排序
    for (int i = 0; i < numsSize - 1; i++) {
        for (int j = 0; j < numsSize - i - 1; j++) {
            if (result[j] > result[j + 1]) {
                int temp = result[j];
                result[j] = result[j + 1];
                result[j + 1] = temp;
            }
        }
    }

    *returnSize = numsSize;  // 将结果数组的大小通过指针参数返回
    return result;  // 返回结果数组的指针
}

 

双指针法 

数组为有序数组, 但负数平方之后可能成为最大数了。

那么数组平方的最大值就在数组的两端,不是最左边就是最右边,不可能是中间。

定义一个新数组result,和A数组一样的大小,让k指向result数组终止位置。

i指向左边,j指向右边。A[i] * A[i] 和A[j] * A[j]进行大小比较,存放在result[k]中。

时间复杂度为O(n) 

int* sortedSquares(int* nums, int numsSize, int* returnSize){
    *returnSize = numsSize; //返回的数组大小就是原数组大小
    int j = numsSize - 1;//右
    int i = 0;//左

    int* result = (int*)malloc(sizeof(int) * numsSize);
    int k;
    for(k = numsSize - 1; k >= 0; k--) {
        if(nums[i] * nums[i] > nums[j] * nums[j]) {
            result[k] = nums[i] * nums[i];
            i++;
        }  //若左指针指向元素平方比右指针指向元素平方大,将左指针指向元素平方放入结果数组。左指针右移一位
        else {
            result[k] =nums[j] * nums[j];
            j--;
        } //若右指针指向元素平方比左指针指向元素平方大,将右指针指向元素平方放入结果数组。右指针左移一位
    }
    return result;
}

 

题目链接

文章链接

视频讲解

209.长度最小的子数组 

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

(我们要找到一个连续子数组,使得从数组中取出该子数组的元素并求和,得到的结果大于等于给定的正整数 s,并且该子数组的长度要尽可能地小。

例如,假设给定数组为 [2, 3, 1, 2, 4, 3],目标正整数为 7。我们可以找到多个满足条件的子数组,如 [2, 3, 1, 2]、[3, 1, 2, 4] 等,但最短的子数组是 [4, 3],其元素之和为 7,因此返回长度 2。)

暴力解法

两层for循环,时间复杂度O(n^2)

内层for循环从起始位置开始,逐个加上后续元素的值,直到总和大于等于给定的正整数 s 或者遍历到数组末尾,如果找到了满足条件的子数组,我们记录下其长度。外层for循环依次向后遍历继续寻找其他满足条件的子数组,并更新最短子数组的长度。最后返回最短子数组的长度。 

  • 时间复杂度:O(n^2)
  • 空间复杂度:O(1)
int minSubArrayLen(int target, int* nums, int numsSize) {
    int minLength = INT_MAX;  // 初始化最短子数组长度为最大值,INT_MAX 是 C 语言中 <limits.h> 头文件中定义的一个常量,表示 int 类型的最大值。
    for (int i = 0; i < numsSize; i++) {  // 枚举子数组的起始位置
        int sum = 0;  // 记录子数组元素之和
        for (int j = i; j < numsSize; j++) {  // 从起始位置开始累加元素
            sum = sum + nums[j];
            if (sum >= target) {  // 如果累加和大于等于s,则更新最短子数组长度
                minLength = fmin(minLength, j - i + 1);//fmin() 是 C 语言中的一个数学函数,它的作用是返回两个数中较小的那个数。
                /*  if (j - i + 1 < minLength) {
                         minLength = j - i + 1;
                }*/

                break;
            }
        }
    }
    return (minLength == INT_MAX) ? 0 : minLength;  // 如果没有找到满足条件的子数组,则返回0
}

滑动窗口 

不断的调节子序列的起始位置和终止位置。

i不变,j不断像后移,如果当前窗口的总值大于s了,i就向后移动。(j是遍历数组的指针,也就是for循环里的索引)

  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

(虽然for循环里嵌套while,但时间复杂度主要是看每一个元素被操作的次数,每个元素在滑动窗后进来操作一次,出去操作一次,每个元素都是被操作两次,所以时间复杂度是 2 × n 也就是O(n) 。暴力解法n × n)

 

 

int minSubArrayLen(int target, int* nums, int numsSize){
    //初始化最小长度为INT_MAX
    int minLength = INT_MAX;
    int sum = 0;

    int i = 0, j = 0;
    //右边界向右扩展
    for(; j < numsSize; j++) {
        sum += nums[j];
        //当sum的值大于等于target时,保存长度,并且收缩左边界
        while(sum >= target) {
            int newLength = j - i + 1;
            minLength = minLength <newLength ? minLength : newLength ;
            sum -= nums[i++];
        }
    }
    //若minLength不为INT_MAX,则返回minLnegth
    return minLength == INT_MAX ? 0 : minLength;
}

 

 题目链接 

 文章链接 

 视频讲解

 59.螺旋矩阵II

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

顺时针画矩阵的过程:每一圈上行从左到右,右列从上到下,下行从右到左,左列从下到上填充。

定义变量 startXstartY 表示每次循环的起始位置,loop 表示循环圈数,offset 偏移值用于控制每一圈的边界向内收缩的单位数,count 表示当前要添加的元素,mid 表示二维数组的中心位置(如果 n 是奇数的话)。

count 的值逐个赋给相应的位置。每一条边都要左闭右开。offset 每次增加 2,startXstartY 每次增加 1,loop 减少 1。循环的圈数loop为n / 2,如果n为奇数,需要最后在中间填入最后一个数字的值。

  • 时间复杂度 O(n^2): 模拟遍历二维矩阵的时间
  • 空间复杂度 O(1)
/**
 * Return an array of arrays of size *returnSize.
 * The sizes of the arrays are returned as *returnColumnSizes array.
 * Note: Both returned array and *columnSizes array must be malloced, assume caller calls free().
 */
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;
    int startY = 0;
    //循环圈数
    int loop = n / 2;
    //设置二维数组的中间值,若n为奇数。需要最后在中间填入数字
    int mid = n / 2;
    //偏移数,每个圈的边界最开始时是向内缩进 1 个单位
    int offset = 1;
    //当前要添加的元素
    int count = 1;

    while(loop) {
        int i = startX;
        int j = startY;
        //模拟上侧从左到右
        for(; j < startY + n - offset; j++) {
            ans[startX][j] = count++;
        }
        //模拟右侧从上到下
        for(; i < startX + n - offset; i++) {
            ans[i][j] = count++;
        }
        //模拟下侧从右到左
        for(; j > startY; j--) {
            ans[i][j] = count++;
        }
        //模拟左侧从下到上
        for(; i > startX; i--) {
            ans[i][j] = count++;
        }
        //偏移值每次加2(每一圈从左到右和从上到下的填充都会占据两个边界的位置)
        offset+=2;
        //遍历起始位置每次+1
        startX++;
        startY++;
        loop--;
    }
    //若n为奇数需要单独给矩阵中间赋值
    if(n%2)
        ans[mid][mid] = count;

    return ans;
}

 

题目链接

文章链接 

视频讲解 

  • 27
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值