代码随想录算法训练营第33期day02:第一章数组part02

977. 有序数组的平方 4分32

给你一个按 非递减顺序 排序的整数数组 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]


解题思想


        根据上一次刷题的总结,采用的是对撞指针,设置 left 和 right 两个指针,left 在数组左端,right 在数组右端,分别比较 left 所指数组元素和 right 所指的数组元素的平方,较大者放入新数组(和所求数组一样长)的尾端。

        为啥这样想呢?因为题中所给的是一个非递减的数组,平方之前最大的数在原数组的右端,但是由于负数的平方是正数且很可能平方之后大于原数组最大数的平方,因此,最左端的数平方之后也有可能成为新数组的最大值,所以考虑对撞指针,另外,由于每次遍历都是求最大的,所以采用倒序的方式为新数组赋值。

vector<int> sortedSquares(vector<int>& nums) {

    int left = 0;
    int right = nums.size() - 1;
    vector<int> res = nums;                         // 新数组
    int k = nums.size() - 1;
    while (left <= right) {                         // 左闭右闭的原则
        int a = nums[left] * nums[left];
        int b = nums[right] * nums[right];
        if (a > b) {								// 取两数平方较大者
            res[k--] = a;
            ++left;
        }
        else {
            res[k--] = b;
            --right;
        }
    }
    return res;
}

收获:又是一道双指针的题,昨天是快慢指针,今天采用的是对撞指针,多用于解决有序数组或者字符串的问题。通过设置两个指针,一个从数组的起始位置开始,一个从数组的结束位置开始,相向移动。


209. 长度最小的子数组 33分59

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


滑动窗口+解题思路


>>固定窗口大小(滑动窗口详解看这个

        由 left 和 right 两个指针所形成的区间,初始时 left 和 right 指向数组的同一个地址,然后 right 指针向右移动,sum 是 left 和 right 所围成的区间的和,当 sum >= target 时,right 不动,left 向右移动,缩小窗口范围来确定符合题目的最小长度。

        本题需要在滑动窗口的模板上稍微改变下,增加对窗口值的判断,以用来求最小的长度。

int minSubArrayLen(int target, vector<int>& nums) {

    // 数组总和小于 target
    int sum = 0;
    for (int i : nums) {
        sum += i;
    }
    if (sum < target) return 0;

    
    int left = 0, right = 0;
    sum = 0; 												// 记录窗口值
    int minLen = nums.size();
    while (right < nums.size()) {
        sum += nums[right++];
        while (sum >= target) {  							// 满足条件,右边界停止移动
            sum -= nums[left++]; 							// 左边界开始缩小
            if (sum < target) {  							// 一旦不符合条件,更新窗口值
                minLen = min(minLen, (right - left + 1));
            }
        }
    }
    return minLen;
}

收获这道题我做的有点久了,而且还是第二次做,上一次的思路基本都忘光了。这道题我觉得还是考察快慢指针,快指针确定窗口的右边界,慢指针最终确定符合条件下的每一轮的最小长度,但是我更倾向于将其归类为固定窗口大小的滑动窗口,滑动窗口是第二次刷了,还需要总结一下。


54. 螺旋矩阵 没想到(;´༎ຶД༎ຶ`)

给你一个 m 行 n 列的矩阵 matrix ,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。

示例 1:

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

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

示例 2:

输入:matrix = [[1,2,3,4],[5,6,7,8],[9,10,11,12]]

输出:[1,2,3,4,8,12,11,10,9,5,6,7]

说明:本来今天卡哥安排的是第 59.螺旋数组II ,但我觉得做之前可以先做下这道,自然就知道那道怎么写了


模拟算法


        模拟算法是指:根据题目提供的信息,将该题目的解决过程模拟出来就能够得到最终的结果,模拟算法比较简单,只要能够根据题目的意思将题目给模拟出来,一般都能够解决这个问题。

根据以上描述我们就可以直到,直到模拟出螺旋矩阵的过程就可以得到最终的结果数组。

vector<int> spiralOrder(vector<vector<int>>& matrix) {

    // 获取矩阵的行列
    int m = matrix.size(), n = matrix[0].size();
    int left = 0, right = n - 1;
    int up = 0, down = m - 1;

    // 结果数组
    vector<int> result;

    while (true) {

        // 上右
        for (int i = left; i <= right; i++) result.push_back(matrix[up][i]);
        if (++up > down) break;			// 上边界下移

        // 右下
        for (int i = up; i <= down; i++) result.push_back(matrix[i][right]);
        if (--right < left) break;      // 右边界左移

        // 下左
        for (int i = right; i >= left; i--) result.push_back(matrix[down][i]);
        if (--down < up) break;			// 下边界上移

        // 左上
        for (int i = down; i >= up; i--) result.push_back(matrix[i][left]);
        if (++left > right) break;      // 左边界右移

    }

    return result;
}

收获:其实这道题一开始我是想要是能够像题中说的和螺旋数组一样就可以了,但是写不出来,就去b站(指路)上看视频讲解,这才直到原来这一类的题目叫做模拟。第一次接触这个算法,算是学习了。其实这个题也挺考验代码能力的,主要是我那个模拟的过程写不出来,这就当是学习了。


59. 螺旋矩阵 II 这道题就直接贴个链接了,思路就是模拟出螺旋矩阵的过程

void createMatrix(vector<vector<int>>& matrix) {

	// 获取矩阵的行列
	int m = matrix.size(), n = matrix[0].size();
	int left = 0, right = n - 1;
	int up = 0, down = m - 1;

	// 用于生成连续的数填充进矩阵
	int k = 1;

	while (true) {

		// 上右
		for (int i = left; i <= right; i++, k++) matrix[up][i] = k;
		if (++up > down) break;			// 上边界下移

		// 右下
		for (int i = up; i <= down; i++, k++) matrix[i][right] = k;
		if (--right < left) break;      // 右边界左移

		// 下左
		for (int i = right; i >= left; i--, k++) matrix[down][i] = k;
		if (--down < up) break;			// 下边界上移

		// 左上
		for (int i = down; i >= up; i--, k++) matrix[i][left] = k;
		if (++left > right) break;      // 左边界右移

	}

}

// 模拟螺旋路径,螺旋式填充数组
vector<vector<int>> generateMatrix(int n) {
	
	// 创建 n 行 n 列的数组 --- 忘记了 
	vector<vector<int>> matrix(n, vector<int>(n, 0));

	// 生成螺旋矩阵  -- 根据 54.螺旋矩阵来写
	createMatrix(matrix);

	// 创建结果数组
	vector<vector<int>> result;
	// 过程数组
	vector<int> path;

	// 一行一行遍历得到结果
	int up = 0, down = n - 1;

	while (true) {
		// 按行遍历
		for (int i = 0; i < n; i++) path.push_back(matrix[up][i]);
		// 写入结果
		result.push_back(path);
		// 清空过程数组
		path.clear(); 
		if (++up > down) break;
	}

	return result;
}

  • 22
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
第二十二天的算法训练营主要涵盖了Leetcode题目中的三道题目,分别是Leetcode 28 "Find the Index of the First Occurrence in a String",Leetcode 977 "有序数组的平方",和Leetcode 209 "长度最小的子数组"。 首先是Leetcode 28题,题目要求在给定的字符串中找到第一个出现的字符的索引。思路是使用双指针来遍历字符串,一个指向字符串的开头,另一个指向字符串的结尾。通过比较两个指针所指向的字符是否相等来判断是否找到了第一个出现的字符。具体实现的代码如下: ```python def findIndex(self, s: str) -> int: left = 0 right = len(s) - 1 while left <= right: if s[left == s[right]: return left left += 1 right -= 1 return -1 ``` 接下来是Leetcode 977题,题目要求对给定的有序数组中的元素进行平方,并按照非递减的顺序返回结果。这里由于数组已经是有序的,所以可以使用双指针的方法来解决问题。一个指针指向数组的开头,另一个指针指向数组的末尾。通过比较两个指针所指向的元素的绝对值的大小来确定哪个元素的平方应该放在结果数组的末尾。具体实现的代码如下: ```python def sortedSquares(self, nums: List[int]) -> List[int]: left = 0 right = len(nums) - 1 ans = [] while left <= right: if abs(nums[left]) >= abs(nums[right]): ans.append(nums[left ** 2) left += 1 else: ans.append(nums[right ** 2) right -= 1 return ans[::-1] ``` 最后是Leetcode 209题,题目要求在给定的数组中找到长度最小的子数组

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值