算法随想Day2【数组】| LC977-有序数组的平方、LC209-长度最小的子数组、LC59-螺旋矩阵Ⅱ

LC977. 有序数组的平方

有了昨天刷题的总结和思考,根据:

  • 条件left <= right,总与右边界right = numsize - 1,nums[right]成对

  • 条件left < right,总与右边界right = numsize,nums[right - 1]成对

比较轻松地解决了容易出错的边界问题

vector<int> sortedSquares(vector<int>& nums)
{
    int left = 0;
    int size = nums.size();
    int right = size;
    int left_square = 0, right_square = 0;
    vector<int> array(size);  //size个元素的vector容器
    while (left < right)
    {
        left_square = nums[left] * nums[left];
        right_square = nums[right] * nums[right];

        if (left_square > right_square)
        {
            array[size - 1] = left_square;
            left++;
        }
        else
        {
            array[size - 1] = right_square;
            right--;
        }
        size--;
    }

    return array;
}

LC209. 长度最小的子数组

开始自己的写法,类似于暴力解法,只不过第二层用了while来表示

////力扣上会超出时间限制
int minSubArrayLen_self(int target, vector<int>& nums)
{
    int size = nums.size();
    int left = 0, right = 0;
    int minlen = size, len_count = 0, val_sum = 0;
    for (; left < size; left++)
    {
        len_count = 0;
        right = left;
        val_sum = nums[left];
        while (val_sum < target)
        {
            right++;
            if (right >= size)
            {
                break;
            }
            val_sum += nums[right];
            len_count++;
        }
        len_count++;

        if (val_sum >= target)
        {
            minlen = len_count < minlen ? len_count : minlen;
        }

        if (val_sum < target && len_count == size)
        {
            return 0;
        }
    }

    return minlen;
}

滑动窗口(双指针)

使用一个for循环完成两个for循环完成的工作,for中的递增变量i应该被视为滑动窗口的终止位置,即end。因为如果视其为起始位置,逐个向后移动,其实跟暴力解法没什么区别。

int minSubArrayLen_slice(int target, vector<int>& nums)
{
    int size = nums.size();
    int start = 0, end = 0;
    int minlen = __INT32_MAX__, len_count = 0, val_sum = 0;
    for (; end < size; end++)
    {
        val_sum += nums[end];   //搜集滑动窗口里的和
        ////一旦和超过target,记录当前长度,左边界缩小
        while (val_sum >= target)  //使用while是因为左边起始位置可能不仅只移动一位
        {
            len_count = end - start + 1;
            minlen = len_count < minlen ? len_count : minlen;
            val_sum = val_sum - nums[start];
            start++; 
        }
    }

    return minlen == __INT32_MAX__ ? 0 : minlen;
}

相关题目推荐

LC59. 螺旋矩阵Ⅱ

没有思路,看Carl讲解。

重点是处理边界条件,坚持“循环不变量”,即像二分法每次分数组都要保持“左闭右闭”或“左闭右开”的原则。

  • 左闭右开

坚持原则:处理一条边的第一个节点,最后一个节点留给下一条边遍历的时候再做处理。

表达一个坐标的数学式为(i,j)。

起始位置:因为每一圈的起始位置都是会改变的,所以for循环中的i和j在循环中就不会是固定的一个值。所以需要在循环外定义一个startx和starty来表示每次循环的起始位置。

终止位置:也是随着每一圈不断地去改变的,每转一圈,终止位置也应该减1,所以需要多一个变量offset来控制它每次循环的终止位置。

对于n * n的一个矩阵,需要转圈赋值的圈数为n / 2圈,若n为奇数,需要最后对矩阵的中心进行单独赋值。

class Solution
{
public:
    /*
        —— —— → y轴(j)
        |
        |
        ↓
        x轴(i)        */
    vector<vector<int>> generateMatrix(int n)
    {
        int i = 0, j = 0;
        int startx = 0, starty = 0;
        int loop = n / 2, count = 1;
        int mid = n / 2;
        int offset = 1;
        vector<vector<int>> array(n, vector<int>(n, 0));  //使用vector定义一个二维数组并初始化为0
        
        ////左闭右开原则
        while (loop--)
        {
            ////每一圈的起始位置会改变,用startx表示
            for (j = starty; j < n - offset; j++)
            {
                array[startx][j] = count++;
            }
            for (i = startx; i < n - offset; i++)  //此时j已经等于n - 1
            {
                array[i][j] = count++;
            }
            for (; j > starty; j--)
            {
                array[i][j] = count++;
            }
            for (; i > startx; i--)
            {
                array[i][j] = count++;
            }

            startx++;
            starty++;
            offset++;
        }

        if (n % 2 == 1)
        {
            array[mid][mid] = count;
        }

        return array;
    }
};

类似题目

  • 54.螺旋矩阵
  • 剑指Offer 29.顺时针打印矩阵
posted @ 2023-02-02 16:52  冥紫将  阅读(67)  评论(0)    收藏  举报