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

977.有序数组的平方

因为是递增且有负数的数组,那么他们的平方如果还是按照原来的顺序排列的话,是两边的值会相对大,所以用两个指针分别从左右两侧寻找新数组里面的元素

我的错误代码:

class Solution {
public:
    vector<int> sortedSquares(vector<int>& nums) {
        int size = nums.size();
        vector<int> result;
        int newIndex = size - 1;
        int left = 0;
        int right = size - 1;

        while(left < right){
            if(nums[left]*nums[left] > nums[right]*nums[right]){
                result[newIndex] = nums[left]*nums[left];
                left++;
            }else{
                result[newIndex] = nums[right]*nums[right];
                right--;
            }
            newIndex--;
        }
        return result;
        
    }
};

代码出现的问题:

1.runtime error: applying non-zero offset 16 to null pointer (stl_vector.h)

        一开始定义vector有问题: vector <int> result(nums.size(),0); 括号里面先是大小,然后是数组的数值

2.while(left < right){  如果没有相等,那就少了left=right指向同一个数组元素的情况了

正确代码如下:

class Solution {
public:
    vector<int> sortedSquares(vector<int>& nums) {
        int size = nums.size();
        vector<int> result(size,0);
        int newIndex = size - 1;
        int left = 0;
        int right = size - 1;

        //如果没有相等,那就少了left=right指向同一个数组元素的情况了
        while(left <= right){
            if(nums[left]*nums[left] > nums[right]*nums[right]){
                result[newIndex] = nums[left]*nums[left];
                left++;
            }else{
                result[newIndex] = nums[right]*nums[right];
                right--;
            }
            newIndex--;
        }
        return result;
        
    }
};

209.长度最小的子数组

1.暴力输出法

用两个for循环输出所有的子集,当找到第一个sum>=target的时候就马上停止,然后需要创建一个sum还有一个子集的长度大小,这样每一个不一样的起始位置之间都可以进行对比,留下来长度最小的那个

接下来又是我的错误代码展示:(好像就没写对过sad)

class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int result = INT_MAX;
        int length = 0;
        int sum = 0;
        int size = nums.size();
        for(int i = 0; i < size; i++){
            for(int j = i; j < size; j++){
                sum += nums[j];
                if(sum >= target){
                    length = j - i + 1;
                    result = result < length ? result : length; //把result的初始值设成一个相对较大的数,这样第一次赋值一定是length
                    break;
                }
            }
        }
        return result == INT_MAX ? 0 : result;
    }
};

错误分析:没有在每一次更换新的起始位置的时候把sum的值重新赋为0,这样的话即使开始新的起始位置,留存的子集还是上一个起始位置时得到的结果,没有办法做到更新

class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int result = INT_MAX;
        int length = 0;
        int sum = 0;
        int size = nums.size();
        for(int i = 0; i < size; i++){
            sum = 0;
            for(int j = i; j < size; j++){
                sum += nums[j];
                if(sum >= target){
                    length = j - i + 1;
                    result = result < length ? result : length; //把result的初始值设成一个相对较大的数,这样第一次赋值一定是length
                    break;
                }
            }
        }
        return result == INT_MAX ? 0 : result;
    }
};

2.滑动窗口法

for循环里面的j表达的是终止位置,起始位置默认从0开始,当终止位置一位一位向前移的时候,直到他们的和 > target,起始默认位置就加1,这样就比暴力解法省去了一个一个代入算的繁琐过程

我的代码终于写对了:

class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int size = nums.size();
        int result = INT_MAX;
        int length = 0;
        int sum = 0;
        int leftIndex = 0;
        for(int i = 0; i < size; i++){
            sum += nums[i];
            while(sum >= target){
                length = i - leftIndex + 1;
                sum -= nums[leftIndex++];
                result = result < length ? result : length;
            }
        }
        return result == INT_MAX ? 0 : result;
    }
};

我觉得这个和暴力解法是有相似处,代码逻辑搞明白之后基本上能立马写出来,就是少了一个for循环的概念


59.螺旋矩阵II

1.需要把1到n平方按照顺时针的方式排列组合,也就是排列成矩阵(二维数组)的模式,经过推演,发现当n为偶数的时候,一共需要转n/2圈,但是当n为奇数的时候( n%2 = 1),还是需要n/2圈(结果为int这个数据类型,会保留整数部分),但是需要把最后一个值放到中间

---->创建二维数组:vector<<int>vector> matrix = (n, vector<int>(n,0))

2.每一行的赋值都要有同一性,在这里我们左闭右开(参考二分法用到的概念),所以平常我们想要取到整行的元素的话,应该是从0开始,i<nums.size(),这样可以取到所有的元素,从0到size-1,但是这一次是左闭右开,也就是右边少取一个,是 i<size-1,要转第二圈的话就是i< size-2。所以这里还要再引入一个offset的概念,每转完一圈,这个offset++

3.需要写四个for循环,左到右,上到下,右到左,下到上

我的错误代码和debug记录:

class Solution {
public:
    vector<vector<int>> generateMatrix(int n) {
        //创建一个二维数组
        vector<vector<int>> matrix = vector(n, vector<int>(n,0));
        //创建每一次赋给数组元素的值
        int val = 1;
        //数组的行列起始index
        int startI = 0;
        int startJ = 0;
        //根据不同的圈,需要减去的会变化的值
        int offset = 1;
        int loop = n/2;
        
        while(loop != 0){
            //赋值给第0行的每一列,所以for循环里面是j
            for(int j = startJ; j < n - offset; j++ ){
                int[i][j] = val++;
            }
            //赋值给第j列的每一行,所以for循环里面是i
            for(int i = startI; i < n - offset; i++ ){
                int[i][j] = val++;
            }
            //赋值给第i行的每一列,所以for循环里面是j,这回往回走,要变成减法了
            for( j = j; j > startJ; j-- ){
                int[i][j] = val++;
            }
            //赋值给第j列的每一行,所以for循环里面是i
            for(i = i; i > startI; i-- ){
                int[i][j] = val++;
            }
            startI++;
            startJ++;
            offset++;
            loop--;

        }
        if(n%2 == 1){
            int[n/2][n/2] = n*n;
        }
        return matrix;

    }
};
  1. 1.error: decomposition declaration cannot be declared with type 'int'; declared type must be 'auto' or reference to 'auto' int[i][j] = val++;  -> 再定义完二维数组之后,应该直接用matrix[i][j],不知道我怎么用了int?
  2. use of undeclared identifier 'i' matrix[i][j] = val++; -> 第一个for循环里面用的是没有定义的i,可以用startI,反正都是对的
  3. error: use of undeclared identifier 'j' matrix[i][j] = val++; -> 同样的错误,如果再用上一把的极值也就是n-offset实在是太麻烦了,所以可以在一开始的时候直接定义好int i,j,这样就可以直接使用了
  4. runtime error: addition of unsigned offset to 0x607000000020 overflowed to 0x606b9b8170b8 (stl_vector.h) -> 出现这个问题说明在给二维数组赋值时的index是有问题的,所以在纸上过了一遍赋值的过程,在最后i和j都会变成0,所以可以是i++,j++,或者 i = startI 和 j =startJ,然后两个start++

在纸上推导的过程:

debug之后的代码:

class Solution {
public:
    vector<vector<int>> generateMatrix(int n) {
        //创建一个二维数组
        vector<vector<int>> matrix = vector(n, vector<int>(n,0));
        //创建每一次赋给数组元素的值
        int val = 1;
        //数组的行列起始index
        int startI = 0;
        int startJ = 0;
        //根据不同的圈,需要减去的会变化的值
        int offset = 1;
        int loop = n/2;
        int i,j;
        
        while(loop != 0){
            i = startI;
            j = startJ;

            //赋值给第0行的每一列,所以for循环里面是j
            for(j = startJ; j < n - offset; j++ ){
                matrix[i][j] = val++;
            }
            //赋值给第j列的每一行,所以for循环里面是i
            for(i = startI; i < n - offset; i++ ){
                matrix[i][j] = val++;
            }
            //赋值给第i行的每一列,所以for循环里面是j,这回往回走,要变成减法了
            for( j = j; j > startJ; j-- ){
                matrix[i][j] = val++;
            }
            //赋值给第j列的每一行,所以for循环里面是i
            for(i = i; i > startI; i-- ){
                matrix[i][j] = val++;
            }
            startI++;
            startJ++;
            offset++;
            loop--;

        }
        if(n%2 == 1){
            matrix[n/2][n/2] = n*n;
        }
        return matrix;

    }
};

可以精进的地方:

1.while后面的括号里面如果只放一个变量,那么就是这个变量为真的时候可以运行,也就是 loop != 0,所以可以直接换成loop

2.while大括号里面的最后需要 loop--,可以直接把这个放在while判断语句的括号里面

3.for循环里面,如果第一个语句不需要给变量赋值,比如在第三四个for循环里面都是 j = j,那么直接不用写这句话也是可以的

最后精进的版本:

class Solution {
public:
    vector<vector<int>> generateMatrix(int n) {
        //创建一个二维数组
        vector<vector<int>> matrix = vector(n, vector<int>(n,0));
        //创建每一次赋给数组元素的值
        int val = 1;
        //数组的行列起始index
        int startI = 0;
        int startJ = 0;
        //根据不同的圈,需要减去的会变化的值
        int offset = 1;
        int loop = n/2;
        int i,j;
        
        while(loop--){
            i = startI;
            j = startJ;

            //赋值给第0行的每一列,所以for循环里面是j
            for(j = startJ; j < n - offset; j++ ){
                matrix[i][j] = val++;
            }
            //赋值给第j列的每一行,所以for循环里面是i
            for(i = startI; i < n - offset; i++ ){
                matrix[i][j] = val++;
            }
            //赋值给第i行的每一列,所以for循环里面是j,这回往回走,要变成减法了
            for( ; j > startJ; j-- ){
                matrix[i][j] = val++;
            }
            //赋值给第j列的每一行,所以for循环里面是i
            for(; i > startI; i-- ){
                matrix[i][j] = val++;
            }
            startI++;
            startJ++;
            offset++;

        }
        if(n%2 == 1){
            matrix[n/2][n/2] = n*n;
        }
        return matrix;

    }
};

总结:

 今日收获:

开始感到学习知识的快乐了,睡觉之前也想要再打开电脑看看,当然学习时间还是挺长的,可能还是6h左右,但是学到了很多东西就不亏,而且这次已经可以在看完carl的视频之后自行写代码了,并且自己debug

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 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题,题目要求在给定的数组中找到长度最小的子数组,使得子数组的和大于等于给定的目标值。这里可以使用滑动窗口的方法来解决问题。使用两个指针来表示滑动窗口的左边界和右边界,通过移动指针来调整滑动窗口的大小,使得滑动窗口中的元素的和满足题目要求。具体实现的代码如下: ```python def minSubArrayLen(self, target: int, nums: List[int]) -> int: left = 0 right = 0 ans = float('inf') total = 0 while right < len(nums): total += nums[right] while total >= target: ans = min(ans, right - left + 1) total -= nums[left] left += 1 right += 1 return ans if ans != float('inf') else 0 ``` 以上就是第二十二天的算法训练营的内容。通过这些题目的练习,可以提升对双指针和滑动窗口等算法的理解和应用能力。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值