有序数组的平方 && 长度最小的子数组 &&螺旋矩阵II

导航

今天这篇主要讲述leetcode题目:
977.有序数组的平方
209.长度最小的子数组
59.螺旋矩阵II

有序数组的平方

题目链接: 977.有序数组的平方
分析过程:
本题应该使用双指针的思路来解答。我的思路是找到绝对值最小值,从其开始往左右移动,每次移动判断左右指针的绝对值,选择就绝对值最小的值,并令指针移动,直到抵达数组两边缘。

时间复杂度:O(n) 空间复杂度O(n)

以下是实现过程代码:

vector<int> sortedSquares(vector<int>& nums)
{
    // 怎么写最大值
    // c <limits.h> INT_MAX
    // c++ <limits> std::numeric_limits<int>::max()
    if (nums.empty()) return nums;

    auto myPingfang = [] (int val) {
        return val * val;
    };
    vector<int> ret;
//    ret.reserve(nums.size());
    ret.resize(nums.size());

    int qbsMin = std::numeric_limits<int>::max();
    int left = 0;
    for (int i = 0; i < nums.size(); ++i) {
        if (std::abs(nums[i]) < qbsMin) {
            qbsMin = std::abs(nums[i]);
            left = i;
        }
    }
    int right = left + 1;
    // 特殊情况
    if (left > 0 && left < nums.size() - 1) {
        if (std::abs(nums[left - 1]) < std::abs(nums[left + 1])){
            right = left;
            left = left - 1;
        }
    }
    int index = 0;
    while (left >= 0 || right < nums.size()) {
        if (left >= 0 && right < nums.size()) {
            if (std::abs(nums[left]) >= std::abs(nums[right])) {
                ret[index++] = myPingfang(nums[right]);
                right++;
            } else {
                ret[index++] = myPingfang(nums[left]);
                left--;
            }
            continue;
        }

        if (left >= 0) {
            ret[index++] = myPingfang(nums[left]);
            left--;
        }
        if (right < nums.size()) {
            ret[index++] = myPingfang(nums[right]);
            right++;
        }
    }
    return ret;
}

代码比较冗余,经过查找资料,可以简化思路如下:
双指针从数组两端向中间靠拢,计算平方并比较大小,并把较大元素放置到数组末端

vector<int> LCFuntion::sortedSquares2(vector<int> &nums)
{
    vector<int> ret(nums.size(), 0);
    int right = nums.size() - 1;
    int index = nums.size() - 1;
    for (int left = 0; left <= right;) {
        if (std::abs(nums[left]) > std::abs(nums[right])) {
            ret[index--] = nums[left] * nums[left];
            left++;
        } else {
            ret[index--] = nums[right] * nums[right];
            right--;
        }
    }
    return ret;
}

长度最小的子数组

题目链接: 209.长度最小的子数组
分析过程:
最简单的解法是暴力遍历,思路是从子数组长度为1到n,分别遍历数组累加,直到找到满足条件时退出遍历,返回结果。
最坏的情况是长度为数组长度n时,时间复杂度为O(n^2)
其实现过程如下:

int minLengthSubArray(vector<int> &nums, int target)
{
    for (int i = 1; i <= nums.size(); ++i) {
        int valSize = i;
        for (int j = 0; j < nums.size() - valSize + 1; ++j) {
            int sum = 0;
            for (int z = 0; z < valSize; ++z)
                sum += nums[j + z];
            if (sum >= target)
                return valSize;
        }
    }
    return 0;
}

那有没有更高效的解法呢?答案是有的
滑动窗口解法:参考文章
滑动窗口的解法是通过一个维护一个滑动窗口,只要遍历一遍数据,不断调整窗口大小,更新最优解。

int minLengthSubArray2(vector<int> &nums, int target)
{
    // [begin, j] 是窗口,begin窗口起点,j终点
    int result = INT_MAX;
    int begin = 0;
    int sum = 0;
    for (auto j = 0; j < nums.size(); ++j) {
        sum += nums[j];
        while (sum >= target) {
            int length = j - begin + 1;
            result = length < result ? length : result;
            sum -= nums[begin];
            begin++;
        }
    }
    return result == INT_MAX ? 0 : result;
}

在使用滑动窗口时,需要确定三个要素:

  1. 窗口是什么?
  2. 窗口的左边界如何移动?
  3. 窗口的右边界如何移动?

本题里 窗口 是满足和大于等于s的子数组,如果子数组和大于等于s了,就需要移动左边界了【即减少窗口大小】,如果数字和小于s,那么就需要移动右边界【增加窗口大小】,就是在这动态的调整窗口过程中,去更新 和大于等于s的子数组 的最优解。

螺旋矩阵II

题目描述: 59.螺旋矩阵II
这个题目的解法需要考虑的边界情况较多,需要仔细了
思路是从最外圈填充元素开始,缩小圈子,直到填充到矩形中心。

vector<vector<int> > turnRect(int n)
{
    vector<vector<int>> ret(n, vector<int>(n, 0));
    int val = 0;
    for (int i = 0; i < n / 2; ++i) {
        // [0,0] - [n,0]
        for (int j = 0; j < n - i; j++) {
            ret[j][i] = val++;
        }
        // [n,0] - [n, n]
        for (int j = 1; j < n - i; ++j) {
            ret[n - 1 - i][j] = val++;
        }
        // [n, n] - [0, n]
        for (int j = n - 2 - i; j >= i; --j) {
            ret[j][n - 1 - i] = val++;
        }
        for (int j = n - 2 - i - 1; j > i; --j) {
            ret[i][j] = val++;
        }
        // [0, n] - [0, 0]
    }
    return ret;
}

总结

  1. vector中使用时区分reserve 和 resize ,reserve后直接[]访问元素是会崩溃的,原因是reserve并没有增加size大小,只是分配好空间,增长是capacity大小
  2. 长度最小的子数组 题目时发现思路有点问题,思路一开始是对的,使用双指针,但是指针从哪开始没有想清楚
  3. sqrt当成平分了,真是自己傻了,题目看起来简单,却耗费了1个多小时才完全作对
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

love_0_love

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值