首页 > 其他分享 >【leetcode_C语言_数组_day2】977.有序数组的平方&&209.长度最小的子数组&&59. 螺旋矩阵 II

【leetcode_C语言_数组_day2】977.有序数组的平方&&209.长度最小的子数组&&59. 螺旋矩阵 II

时间:2022-10-16 11:56:13浏览次数:79  
标签:977 窗口 数组 nums int MAX INT &&

977.有序数组的平方

1. 题目

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

示例 1:

输入:nums = [-4,-1,0,3,10]
输出:[0,1,9,16,100]
解释:平方后,数组变为 [16,1,0,9,100]
排序后,数组变为 [0,1,9,16,100]

示例 2:

输入:nums = [-7,-3,2,3,11]
输出:[4,9,9,49,121]

2. 分析

写法1:暴力排序

​ 直接平方后排序。注意这里不可以用冒泡排序,冒泡排序双循环,复杂度n^2。这里要用qosrt

重点:调用qsort函数

​ 调用qsort函数,要先写出cmp函数的定义。固定格式。

int cmp(const void * _a,const void *_b)
{
    return (*(int*)_a - *(int*)_b);
}
int* sortedSquares(int* nums, int numsSize, int* returnSize){

    int i,j;
    (*returnSize)=numsSize;
    int temp;
    int* ans = (int*)malloc(sizeof(int) * numsSize);
    for(i=0;i<numsSize;i++)
    {
        ans[i]=nums[i]*nums[i];
    }
    qsort(ans,numsSize,sizeof(int),cmp);
    return ans;
}

for循环的复杂度是n,qsort的复杂度是nlogn,可以把整体的复杂度看出nlogn。

写法2:双指针法

数组其实是有序的, 只不过负数平方之后可能成为最大数了。

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

此时可以考虑双指针法了,i指向起始位置,j指向终止位置。

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

如果A[i] * A[i] < A[j] * A[j] 那么result[k--] = A[j] * A[j];

如果A[i] * A[i] >= A[j] * A[j] 那么result[k--] = A[i] * A[i];

如动画所示:

img

int* sortedSquares(int* nums, int numsSize, int* returnSize){
    (*returnSize)=numsSize;
    int left,right;
    left=0;right=numsSize-1;
    int index;
    //首先要设立三个指针:左指针,右指针,和新数组ans的指针
    int *ans=(int*)malloc(sizeof(int)*numsSize);
    //新建数组ans,并开辟一份空间
    for(index=numsSize-1;index>=0;index--)
    {
        if(nums[left]*nums[left]<nums[right]*nums[right])//左指针平方比右指针的平方小
        {
            ans[index]=nums[right]*nums[right];//把右指针的平方赋给新数组
            right--;//右指针左移
        }
        else//否则
        {
            ans[index]=nums[left]*nums[left];//把左指针的平方赋给新数组
            left++;//左指针右移
        }
    }
    return ans;//返回新的数组
}

209.长度最小的子数组

1. 题目

给定一个含有 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

2. 分析

写法1:暴力排序(O(n^2),不会通过)

int minSubArrayLen(int target, int* nums, int numsSize){
    int sum;
    int i,j;
    int len=65535;
    for(i=0;i<numsSize;i++)
    {
        sum=0;
        for(j=i;j<numsSize;j++)
        {
            sum=sum+nums[j];
            if(sum>=target&&(j-i+1)<=len)//连续子数组的和如果大于target且长度小于上一个len
            {//j-i+1 是子序列的长度
                len=j-i+1;//那么更新len
                break;//并且跳出
            }
        }
    }
    if(len==65535) len=0;//如果len没有被更新过,说明没有满足条件的连续数组
    return len;
}
image-20221015190637205

写法2:滑动窗口

​ 滑动窗口和双指针的思想类似。

​ 滑动窗口,就是不断的调节子序列的起始位置和终止位置,从而得出我们要想的结果

​ 滑动窗口如何用一个for循环来完成这个操作呢。

首先要思考 如果用一个for循环,那么应该表示 滑动窗口的起始位置,还是终止位置。

只用一个for循环,那么这个循环的索引,一定是表示 滑动窗口的终止位置。

那么问题来了, 滑动窗口的起始位置如何移动呢?

这里还是以题目中的示例来举例,s=7, 数组是 2,3,1,2,4,3,来看一下查找的过程

209.长度最小的子数组

最后找到 4,3 是最短距离。

在本题中实现滑动窗口,主要确定如下三点:

  • 窗口内是什么?
  • 如何移动窗口的起始位置?
  • 如何移动窗口的结束位置?

窗口就是 满足其和 ≥ s 的长度最小的 连续 子数组。

窗口的起始位置如何移动:如果当前窗口的值大于s了,窗口就要向前移动了(也就是该缩小了)。

窗口的结束位置如何移动:窗口的结束位置就是遍历数组的指针,也就是for循环里的索引。

int minSubArrayLen(int target, int* nums, int numsSize){
    int start,end;
    //滑动窗口的起始位置和终止位置
    start=0;end=0;
    int sum=0;

    int len=INT_MAX;//易错点
    for(;end<numsSize;end++)//只需要一层对end指针的循环,即滑动窗口的终止位置的索引
    {
        sum+=nums[end];//sum:对窗口内的值累加
        while(sum>=target)//当窗口满足大于等于target的值就要缩小窗口了。
        {//注意用的是while。
            if(len>=end-start+1)//end-start+1 是子序列的长度,即窗口的长度
            {
                len=end-start+1;//更新长度,直到最小长度
            }
            sum=sum-nums[start];//缩小窗口的同时要把sum也缩小了
            start++;//起始位置右移
        }
    }
    if(len==INT_MAX) len=0;//如果len没有被更新过,说明没有满足条件的连续数组
    return len;
}

程序中加了while的复杂度不一定会是O(n^2)。需要关注每个元素被操作的次数。

此程序中,每个元素在滑动窗后进来操作一次,出去操作一次,每个元素都是被操作两次,所以时间复杂度是 2 × n 也就是O(n)。

易错点:len=INT_MAX是稳定的写法,自己写的65535会报错

C中常量INT_MAX和INT_MIN分别表示最大、最小整数,定义在头文件limits.h中。

  1. INT_MAX,INT_MIN数值大小:
    因为int占4字节32位,根据二进制编码的规则,INT_MAX = 2^31-1,INT_MIN= -2^31

  2. 关于INT_MAX INT_MIN的运算
    由于二进制编码按原码、补码和反码的规则进行运算,所有程序中对INT_MAX和INT_MIN的运算应当格外注意,在出现溢出的时候,不遵循数学规则。

​ INT_MAX + 1 = INT_MIN

​ INT_MIN - 1 = INT_MAX

​ abs(INT_MIN) = INT_MIN

​ 比较有趣的是,INT_MAX + 1 < INT_MAX, INT_MIN - 1 > INT_MIN, abs(INT_MIN) < 0.


版权声明:本文为CSDN博主「zhusf16」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u012604810/article/details/80290706

59. 螺旋矩阵 II

1. 题目

给你一个正整数 n ,生成一个包含 1n2 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix

示例 1:

img

输入:n = 3
输出:[[1,2,3],[8,9,4],[7,6,5]]

示例 2:

输入:n = 1
输出:[[1]]

2. 分析

可以总结出一圈下来,需要画四条边。这四条边都要用固定的规则来遍历!

img

  1. 经过观察,比如n=3时,每条边可以划分为边长为2的边。所以需要考虑边界的判定条件。边界条件需要依据循环不变量的原则,统一实行左闭右开。

  2. 其次,当n=4时,我们可以观察到需要画两圈。所以n不同,循环圈数也不同。设置变量循环圈数loop。loop=n/2。

  3. 在第二圈的时候,初始位置从(0,0)变成了(1,1)。所以需要设置变量startX,startY确定初始位置。在进入下一圈前,startX+1,startY+1。

  4. 当n=4时,在第二圈的时候,边长比第一圈-1了。所以需要设置偏移量offset。在进入下一圈前,offset+1。

  5. 每一圈的操作都是模拟顺时针画矩阵的过程:

  • 填充上行从左到右

  • 填充右列从上到下

  • 填充下行从右到左

  • 填充左列从下到上

    所以while循环的判定条件是按圈来的。while(loop--)。

    循环结束的最后,把最后一个值写入矩阵的最中间的值。这个部分需要最后另外写入。

3.知识补充:二维数组开辟存储空间

image-20221016113749707

先看一下用malloc申请一维数组:

int *p=(int *)malloc(n*sizeof(int));//开辟n个内存空间

首先申请n个指针数组(不是数组指针)int *,既然是指针数组,存放的都是指针,那么我们就可以在此基础上继续开辟n个内存空间。由此构成了n * n的二维数组空间。

    int **ans=(int*)malloc(sizeof(int*)*n);//申请指针数组
    for(i=0;i<n;i++)
    {
        ans[i]=(int*)malloc(sizeof(int)*n);//再申请n个内存空间
    }

参考博客:

(14条消息) 用malloc开辟二维数组的三种办法_张淑芬~的博客-CSDN博客_malloc二维数组

/**
 * 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);
    int **ans=(int*)malloc(sizeof(int*)*n);//开辟新空间

    int i,j;
    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;//循环圈数
    int offset=1;//每一圈的边长都需要调整,所以需要offset偏移数
    int mid=n/2;//中间值的坐标。中间值需要最后另外写入
    int count=1;//待写入的数值

    while(loop--)
    {
        i=startX;
        j=startY;
        //上行:从左到右
        for(j=startY;j<n-offset;j++)
            ans[i][j]=count++;

        //右列:从上到下
        for(i=startX;i<n-offset;i++)
            ans[i][j]=count++;

        //下行:从右到左
        for(;j>startY;j--)
            ans[i][j]=count++;

        //左列:从上到下
        for(;i>startX;i--)
            ans[i][j]=count++;

        //从第二圈开始,起始位置都要+1
        //例如,第一圈起始位置(0,0)第二圈起始位置(1,1)
        startX++;
        startY++;
        //第二圈开始,边长-1,所以要修正
        offset +=1;
        
    }
    if(n%2)
        ans[mid][mid]=count;

    return ans;
}

标签:977,窗口,数组,nums,int,MAX,INT,&&
From: https://www.cnblogs.com/MLcaigou/p/16795884.html

相关文章

  • C语言之字符串与字符数组的区别
     1.字符串的定义:(1)单个字符:charch='i';//单个字符的定义(2)一维字符串数组:chararr[]="love";(这种方法定义的一维字符串数组必须赋值)chararr[4];(想内存申请创建可以......
  • 748. 数组的右下半部分
    文章目录​​Question​​​​Ideas​​​​Code​​Question输入一个二维数组M[12][12],根据输入的要求,求出二维数组的右下半部分元素的平均值或元素的和。右下半部分是指......
  • 747. 数组的左上半部分
    文章目录​​Question​​​​Ideas​​​​Code​​Question输入一个二维数组M[12][12],根据输入的要求,求出二维数组的左上半部分元素的平均值或元素的和。左上半部分是指......
  • javascript 数组
    javascript数组文章目录​​javascript数组​​​​1.简介​​​​2.创建数组​​​​3.访问数组​​​​4.数组方法和属性​​​​5.创建新方法​​​​6.实例​​......
  • 1441. 用栈操作构建数组
    1441.用栈操作构建数组给你一个数组target和一个整数n。每次迭代,需要从 list={1,2,3...,n}中依次读取一个数字。请使用下述操作来构建目标数组targ......
  • DS | 一维数组 & 二维数组 & 对称矩阵 & 三角矩阵 & 三对角矩阵地址的计算
    一维数组的地址计算设每个元素的大小是\(size\),首元素的地址是\(a[1]\),则a[i]=a[1]+(i-1)*size若首元素的地址是\(a[0]\)则a[i]=a[0]+i*size二维数组的地......
  • 初识C语言(2)——数组、操作符、关键字
    ......
  • 用栈操作构建数组
    给你一个数组target和一个整数n。每次迭代,需要从 list={1,2,3...,n}中依次读取一个数字。请使用下述操作来构建目标数组target:"Push":从list中读取一个......
  • 零一背包问题,滚动数组实现
    其实最难理解的内循环,也就是j的循环。j的条件是大于w[i],而w[i]则是当前第i个物品的重量,则j是一在从背包容量,向j-w[i]靠近。j-w[i]就是剩下来的空间,而这一波操作......
  • 校验数组是否为空
    校验数组是否为空constisNotEmpty=arr=>Array.isArray(arr)&&!!arr.length;isNotEmpty([1,2,3]);//Result:true回到顶部functiontopFunction(){d......