(二)|977.有序数组的平方 ,209.长度最小的子数组 ,59.螺旋矩阵

977.有序数组的平方

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

对数组进行排序的方法:

方法一:冒泡排序

  1. 比较相邻的元素。如果第一个比第二个大,就交换他们两个。

  2. 对每一对相邻元素做同样的工作,执行完毕后,找到第一个最大值。

  3. 重复以上的步骤,每次比较次数-1,直到不需要比较

  4. 外层循环i<nums.size()-1;内层循环j<nums.size()-1-i

    #include<iostream>
     
    using namespace std;
     
    int main() {
     
    	int arr[9] = { 4,2,8,0,5,7,1,3,9 };
     
    	for (int i = 0; i < 9 - 1; i++)
    	{
    		for (int j = 0; j < 9 - 1 - i; j++)
    		{
    			if (arr[j] > arr[j + 1])
    			{
    				int temp = arr[j];
    				arr[j] = arr[j + 1];
    				arr[j + 1] = temp;
    			}
    		}
    	}
     
    	for (int i = 0; i < 9; i++)
    	{
    		cout << arr[i] << endl;
    	}
        
    	system("pause");
     
    	return 0;
    }

    方法二:sort函数

  5. 但是sort函数默认升序排列, 可以使用greater<int>()降序排列:sort(arr,arr+5,greater<int>());

  6. #include<iostream>
    #include<algorithm>
    using namespace std;
    int main()
    {
      int arr[]={2,4,5,3,1};
      sort(arr,arr+5);
      for(int i=0;i<5;i++)
    {
      cout<<arr[i];
      return 0;
    }

    这道题如果这么解:结果会超出时间限制!为什么?

    class Solution {
    public:
        vector<int> sortedSquares(vector<int>& nums) {
        for(int i=0;i<nums.size();i++)
        {
            nums[i]=nums[i]*nums[i];
        }
        for(int i=0;i<nums.size()-1;i++)
        {
            for(int j=0;j<nums.size()-1-i;j++)
            {
                if(nums[j]>nums[j+1])
                {
                    int temp=nums[j];
                    nums[j]=nums[j+1];
                    nums[j+1]=temp;
                }
            }
        }
        return nums;
    }
    };

    采用sort函数解:

    class Solution {
    public:
        vector<int> sortedSquares(vector<int>& nums) {
        for(int i=0;i<nums.size();i++)
        {
            nums[i]=nums[i]*nums[i];
            
        }
        sort(nums.begin(),nums.end());
        return nums;
    }
    };

    双指针法:

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

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

    此时可以考虑双指针法了,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]; 。 

class Solution {
public:
    vector<int> sortedSquares(vector<int>& nums) {
    vector<int>result(nums.size(),0);//定义一个result数组,大小等于nums数组的大小,初始化值都是0
    int k=result.size()-1;//k为result数组的下标,因为值是从大到小判断出来的,所以值倒序输入到result数组中,最大值存到最后一位
    for(int i=0,j=nums.size()-1;i<=j;)
    {
        if(nums[i]*nums[i]>nums[j]*nums[j])
        {
            result[k]=nums[i]*nums[i];
            i++;
            k--;
        }
        else
        {
            result[k]=nums[j]*nums[j];
            k--;
            j--;
        }
    }
    return result;
}
};

python中创建制定长度和初值的列表:

#一维列表的创建:
    a = [None] * n  # 创建一个初值为None的长度为n的列表a,None只是一种初值也可换成其他的初值。 

# 二维列表的创建:
    a = [[0 for col in range(m)] for row in range(n)]  # 创建一个n*m的二维矩阵a,每个初值都是0 

class Solution(object):
    def sortedSquares(self, nums):
        left=0
        right=len(nums)-1
        i=len(nums)-1
        result=[None]*len(nums)#创建一个和原数组长度相等且初始值为None的数组接收最终结果
        while left<=right:
            if nums[left]**2>nums[right]**2:
                result[i]=nums[left]**2
                left +=1
            else:
                result[i]=nums[right]**2
                right -=1
            i -=1
        return result

 

209.长度最小的子数组 

题目描述:

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

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

 暴力解法:会超时

两层for循环:外循环i从0开始,内循环从i开始逐渐往后移动,并判断nums[i]+nums[j]是否达到目标值,如果大于等于target,记录下此时的数组长度,跳出此次循环;然后移动i,移动j,如果又找到了满足条件的数组,和之前的数组长度进行比较,取最小的。

class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int len=0;
        int result=INT32_MAX;//INT32_MAX是C/C++语言中预定义的一个常量,它代表了32位有符号整数类型(int)所能表示的最大值,即2147483647
        for(int i=0;i<nums.size();i++)
        {
            int sum=0;
            for(int j=i;j<nums.size();j++)
            {
                sum+=nums[j];
                if(sum>=target)
                {
                    len=j-i+1;
                    if(len<result)result=len;
                    break;
                }
            }
        }
        if(result==INT32_MAX)return 0;
        else{return result;}
    }
};

注:

INT32_MAX是C/C++语言中预定义的一个常量,它代表了32位有符号整数类型(int)所能表示的最大值,即2147483647

暴力解法二:

class Solution {
public:
    int minSubArrayLen(int s, vector<int>& nums) {
        int result = INT32_MAX; // 最终的结果
        int sum = 0; // 子序列的数值之和
        int subLength = 0; // 子序列的长度
        for (int i = 0; i < nums.size(); i++) { // 设置子序列起点为i
            sum = 0;
            for (int j = i; j < nums.size(); j++) { // 设置子序列终止位置为j
                sum += nums[j];
                if (sum >= s) { // 一旦发现子序列和超过了s,更新result
                    subLength = j - i + 1; // 取子序列的长度
                    result = result < subLength ? result : subLength;
                    break; // 因为我们是找符合条件最短的子序列,所以一旦符合条件就break
                }
            }
        }
        // 如果result没有被赋值的话,就返回0,说明没有符合条件的子序列
        return result == INT32_MAX ? 0 : result;
    }
};

注:

result = result < subLength ? result : subLength;

如果result<subLength,result更新为 subLength,否则result=result;

return result == INT32_MAX ? 0 : result;

判断result是否还是最大值,如果是return 0,否则return result.

也就是说这个语法的意思是,如果满足条件就返回:左边的值,不满足条件就返回:右边的值 

滑动窗口法: 

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

在暴力解法中,是一个for循环滑动窗口的起始位置,一个for循环为滑动窗口的终止位置,用两个for循环 完成了一个不断搜索区间的过程。

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

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

如果只用一个for循环来表示 滑动窗口的起始位置,那么如何遍历剩下的终止位置?

此时难免再次陷入 暴力解法的怪圈。

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

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

  • 窗口内是什么?
  • 如何移动窗口的起始位置?
  • 如何移动窗口的结束位置?
  1. 窗口就是 满足其和 ≥ s 的长度最小的 连续 子数组。
  2. 窗口的起始位置如何移动:如果当前窗口的值大于s了,窗口就要向前移动了(也就是该缩小了)。
  3. 窗口的结束位置如何移动:窗口的结束位置就是遍历数组的指针,也就是for循环里的索引。

解题的关键在于 窗口的起始位置如何移动,如图所示:

class Solution {
public:
    int minSubArrayLen(int s, vector<int>& nums) {
        int result = INT32_MAX;
        int sum = 0; // 滑动窗口数值之和
        int i = 0; // 滑动窗口起始位置
        int subLength = 0; // 滑动窗口的长度
        for (int j = 0; j < nums.size(); j++) {
            sum += nums[j];
            // 注意这里使用while,每次更新 i(起始位置),并不断比较子序列是否符合条件
            while (sum >= s) {
                subLength = (j - i + 1); // 取子序列的长度
                result = result < subLength ? result : subLength;
                sum -= nums[i++]; // 这里体现出滑动窗口的精髓之处,不断变更i(子序列的起始位置)
            }
        }
        // 如果result没有被赋值的话,就返回0,说明没有符合条件的子序列
        return result == INT32_MAX ? 0 : result;
    }
};
  • 使用while是因为:移动完i之后 ,仍然要继续判断缩小后的窗口里的值之和是否大于等于s,如果还大于等于s,则继续移动窗口的起始位置,即继续缩小窗口,即持续进行这个过程;如果使用if的话,如果sum>=s,更新完i之后就不再继续判断缩小后的窗口里的值之和是否大于等于s,而是去移动终止位置了。
  • sum-=nums[i++];//等同于sum-=nums[i];i++; 

Python解法(自己的解法):

class Solution(object):
    def minSubArrayLen(self, target, nums):
        i=0
        k=0
        sum=nums[0]
        size=len(nums)
        count=1
        result=[]
        while i<=k and k<size:
            if sum<target:
                k+=1
                if k<size:
                    count+=1
                    sum+=nums[k]
            else:
                result.append(count)
                sum-=nums[i]
                i+=1
                count-=1
        if result:
            result=sorted(result)
            return result[0]
        else:
            return 0

 59.螺旋矩阵

题目描述:

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

class Solution {
public:
    vector<vector<int>> generateMatrix(int n) {
        vector<vector<int>> res(n, vector<int>(n, 0)); // 使用vector定义一个二维数组
        int startx = 0, starty = 0; // 定义每循环一个圈的起始位置
        int loop = n / 2; // 每个圈循环几次,例如n为奇数3,那么loop = 1 只是循环一圈,矩阵中间的值需要单独处理
        int mid = n / 2; // 矩阵中间的位置,例如:n为3, 中间的位置就是(1,1),n为5,中间位置为(2, 2)
        int count = 1; // 用来给矩阵中每一个空格赋值
        int offset = 1; // 需要控制每一条边遍历的长度,每次循环右边界收缩一位
        int i,j;
        while (loop --) {
            i = startx;
            j = starty;

            // 下面开始的四个for就是模拟转了一圈
            // 模拟填充上行从左到右(左闭右开)
            for (j = starty; j < n - offset; j++) {
                res[startx][j] = count++;
            }
            // 模拟填充右列从上到下(左闭右开)
            for (i = startx; i < n - offset; i++) {
                res[i][j] = count++;
            }
            // 模拟填充下行从右到左(左闭右开)
            for (; j > starty; j--) {
                res[i][j] = count++;
            }
            // 模拟填充左列从下到上(左闭右开)
            for (; i > startx; i--) {
                res[i][j] = count++;
            }

            // 第二圈开始的时候,起始位置要各自加1, 例如:第一圈起始位置是(0, 0),第二圈起始位置是(1, 1)
            startx++;
            starty++;

            // offset 控制每一圈里每一条边遍历的长度
            offset += 1;
        }

        // 如果n为奇数的话,需要单独给矩阵最中间的位置赋值
        if (n % 2) {
            res[mid][mid] = count;
        }
        return res;
    }
};

 vector<vector<int>> res(n, vector<int>(n, 0))是创建了一个n行n列,全为0的二维数组

// 将二维数组v,初始化为m行n列,全为0,写法如下:

vector<vector<int>> v(m, vector<int>(n,0));

错误写法:为什么?

class Solution {
public:
    vector<vector<int>> generateMatrix(int n) {
    vector<vector<int>> res(n,vector<int>(n,0));
    int loop=n/2;
    int startx=0;
    int starty=0;
    int count=1;
    int mid=n/2;
    int offset=1;
    int i,j;
    while(loop--)
    {
      i=startx;
      j=starty;
        for(int j=starty;j<n-offset;j++)//for循环里写int j就不对
        {
            res[startx][j]=count;
            count++;
        }
        for(int i=startx;i<n-offset;i++)//for循环里写int i就不对
        {
            res[i][j]=count;
            count++;
        }
         for(;j>starty;j--)
        {
            res[i][j]=count;
            count++;
        }
        for(;i>startx;i--)
        {
            res[i][j]=count;
            count++;
        }
        startx++;
        starty++;
        offset++;
       
    }
    if(n%2==1)
    {res[mid][mid]=count;}
    return res;
}
};

Python:

想要构建一个m行n列的二维数组

L = [[ ] * n] * m

如果想要给一个初始化的值,可以写成:

L = [[0] * n] * m

但是,由于此方法构造的二维数组是对[]*n引用了m次,更改其中一行的值会导致每行的值都被更改。所以,并不是一个可以完全操控到列粒度的二维数组

注意:区分nums = [[0] * n] * n和nums = [[0] * n for _ in range(n)] 

nums = [[0] * n for _ in range(n)] 

这行代码创建了一个二维列表 nums,其中包含 n 行和 n 列,并且每个元素都被初始化为 0。

让我们逐步解释这行代码:

range(n) 创建一个包含从 0 到 n-1 的整数序列。在这个例子中,它用于控制列表的行数和列数。

for _ in range(n) 使用 _(一个通常用于表示不需要使用的变量的惯用方法)迭代整数序列,即对每一行进行迭代。

[0] * n 创建一个包含 n 个零的列表,即一行的元素。

整个表达式 [[0] * n for _ in range(n)] 使用列表推导式,通过在每一行都复制 [0] * n,最终创建了一个 n x n 的二维列表,其中每个元素都是 0。

这种方式是在初始化矩阵或二维数组时的一种简洁的方法,特别是在 Python 中,可以避免常见的嵌套列表问题。

 nums = [[0] * n] * n

nums = [[0] * n] * n 创建了一个包含 n 行的二维列表,其中每一行都是对相同的 [0] * n 列表的引用。这意味着如果修改其中一个行的值,所有行都会受到影响,因为它们引用的是同一个列表对象

n = 3
nums = [[0] * n] * n
nums[0][0] = 1

print(nums)
# 输出:
# [[1, 0, 0], [1, 0, 0], [1, 0, 0]]

相比之下,nums = [[0] * n for _ in range(n)] 使用列表推导式为每一行都创建了一个新的 [0] * n 列表。这样,每一行都是独立的,修改一行不会影响其他行 。

n = 3
nums = [[0] * n for _ in range(n)]
nums[0][0] = 1

print(nums)
# 输出:
# [[1, 0, 0], [0, 0, 0], [0, 0, 0]]

 

class Solution(object):
    def generateMatrix(self, n):
        startx=0
        starty=0
        loop=n//2
        mid=n//2
        nums=[[0]*n for _ in range(n)]
        count=1
        for offset in range(1,loop+1):
            for i in range(startx,n-offset):
                nums[startx][i]=count
                count+=1
            for i in range(starty,n-offset):
                nums[i][n-offset]=count
                count+=1
            for i in range(n-offset,starty,-1):
                nums[n-offset][i]=count
                count+=1
            for i in range(n-offset,startx,-1):
                nums[i][starty]=count
                count+=1
            startx+=1
            starty+=1
        if n%2!=0:
            nums[mid][mid]=count
        return nums

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值