小白刷代码随想录day2 -- 977有序数组的平方,209 长度最小的子数组,59 螺旋矩阵||

今天第二天刷题,基础欠缺还很多,慢慢一点一点补!加油!今天主要学习整理977,快速学习209和59。

977 有序数组的平方

题目

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

示例 1:

输入:nums = [-4,-1,0,3,10]

输出:[0,1,9,16,100]

解释:平方后,数组变为 [16,1,0,9,100]

排序后,数组变为 [0,1,9,16,100]

https://leetcode.cn/problems/squares-of-a-sorted-array

初始思路

根据提示使用双指针,定义了一个快指针一个慢指针分别比较前一个元素和后一个元素,将最小值赋给慢指针,再将慢指针的值赋给下标为0的元素,以此类推。

看上去思路好像还行,但实际写起来并没有写成功,可能还需要继续改进,也可能这个思路本身存在着问题。(留待以后继续写写看)。但很明显的是,就算这个思路可行,其时间复杂度也会很大,不是一个很理想的解。

初始解题时发现的点

  1. 平方的运算:java中求整数a的平方不能写为a^2。详细参照http://t.csdn.cn/WgbU4。a的平方运算应该为a*a 或 Math.pow(n,2)。

  1. 运行中出现了Exception in thread “main“ java.lang.ArrayIndexOutOfBoundsException:Index 5 out of bounds for length报错。原代码如下:

for(int i =1; i < nums.length; i++){
            int fast, slow = 0;
            fast = nums[i+1]*nums[i+1];
            slow = nums[i]*nums[i];

通过参照http://t.csdn.cn/VCWB4发现问题出现在fast中nums[i+1]的下标已经在i=nums.length时会超出数组大小,因此会报错。因此可以改为:

for(int i =1; i < nums.length; i++){
            int fast, slow = 0;
            fast = nums[i]*nums[i];
            slow = nums[i-1]*nums[i-1];

回到题目,让我们来学习Leetcode官方给出的解题方法:

方法1  直接排序

将数组nums中的数平方后用Arrays.sort直接排序

class Solution {
    public int[] sortedSquares(int[] nums) {
        int[] ans = new int[nums.length];
        for (int i = 0; i < nums.length; ++i) {
            ans[i] = nums[i] * nums[i];
        }
        Arrays.sort(ans);
        return ans;
    }
}

作者:LeetCode-Solution

时间复杂度:O(nlogn), 空间复杂度:O(logn) 【需要logn的栈空间进行排序】

Arrays.sort() 默认将数组从小到大进行排序。其根据数据量级选择插入、归并和快速排序,时间复杂度为O(nlogn)。

方法二 双指针(赋值最小值)

可以用双指针的条件为已知数组为非降序(升序)排列。方法二设neg为数组nums中负数与非负数的分界线。nums[0]nums[neg] 均为负数,nums[neg+1] 到 nums[n-1] 均为非负数。因此我们可以以negneg+1为双指针分别在负数区域和非负数区域运动,比较平方的大小。

  • 指针neg从负数区域的最右侧往左移neg最初所指的元素一定为负数区域中平方后的最小数。

  • 指针neg+1从非负数区域最左侧往右移neg+1最初所指的元素一定为非负数区域中平方后的最小数。

因此,比较两个指针所指的平方的大小,将最小值赋给输出的新数组ans的第一个值, 以此类推进行比较和循环。

class Solution {
    public int[] sortedSquares(int[] nums) {
        int n = nums.length;
        int negative = -1;
        for (int i = 0; i < n; ++i) {
            if (nums[i] < 0) {
                negative = i;
            } else {
                break;
            }
        }

        int[] ans = new int[n];
        int index = 0, i = negative, j = negative + 1;
        while (i >= 0 || j < n) {
            if (i < 0) {
                ans[index] = nums[j] * nums[j];
                ++j;
            } else if (j == n) {
                ans[index] = nums[i] * nums[i];
                --i;
            } else if (nums[i] * nums[i] < nums[j] * nums[j]) {
                ans[index] = nums[i] * nums[i];
                --i;
            } else {
                ans[index] = nums[j] * nums[j];
                ++j;
            }
            ++index;
        }

        return ans;
    }
}

作者:LeetCode-Solution

时间复杂度O(n),空间复杂度O(1)

方法三 双指针(赋值最大值)

两个指针分别指向位置0n-1。如下图所示。

无论何种情况,数组位于位置0n-1的两个元素中的一个一定是平方后的最大值。此方法避免了方法二去寻找负数和非负数的临界点。两个指针所指的元素平方后谁更大谁写入输出数组ans的最后一位pos。这样答案就被逆序放入数组ans中。

代码如下:

class Solution {
    public int[] sortedSquares(int[] nums) {
        int n = nums.length;
        int[] ans = new int[n];
        for (int i = 0, j = n - 1, pos = n - 1; i <= j;) {
            if (nums[i] * nums[i] > nums[j] * nums[j]) {
                ans[pos] = nums[i] * nums[i];
                ++i;
            } else {
                ans[pos] = nums[j] * nums[j];
                --j;
            }
            --pos;
        }
        return ans;
    }
}

作者:LeetCode-Solution

时间复杂度O(n), 空间复杂度O(1)

209 长度最小的子数组

看了卡哥的视频https://www.bilibili.com/video/BV1tZ4y1q7XE/?vd_source=2b661ed7e8639bf2834608f46f8c8d5f,没有写代码。后面有时间自己再写一写。

滑动窗口

本题的思路为滑动窗口。其实可以理解为双指针及其中间的集合。

要点总结:

1.  两个指针:起始指针、终点指针

2. j为终点指针

3. 先移动终点指针,当集合的和sum>=target后再移动起始指针

4. 判断sum >= s用while循环而不用if,因为要保证起始指针持续地向后移动

59 螺旋矩阵||

看到题给我惊呆了,看完解法又给我惊呆了。https://www.bilibili.com/video/BV1SL4y1N7mV/?spm_id_from=333.788&vd_source=2b661ed7e8639bf2834608f46f8c8d5f。视频看懂了,后面试着自己写一写。

边界处理--循环不变量

本题的主要思路 --模拟转圈,边界处理问题。坚持循环不变量原则。

循环不变量,即坚持用同一个规则处理每一条边。采用“左闭右开”规则。永远不处理每条边的最后一个节点。把它留给下一条边作为起始点。

要点总结:

  1. while进入循环,n/2判断转几圈。若n为奇数,则在后面把多出来的数加上;

  1. j遍历横线上的点, i遍历竖线上的点;

  1. 每次循环的起始点为(start x,start y),初始start x,start y都等于0。后面start x++, start y++,下一个循环开始。

  1. 每一圈想要做到左闭右开的“右开”, i或j最大都不能超过n-offset。减去offset即要减去最后一个节点。(我一开始在想为什么不直接定义offset为1,后来发现offset只有第一圈的时候为1,到转到第二圈也就是再往里面螺旋的时候,随着圈的缩小需要减去的offset也要变多。因此设置offset方便调试。将初始offset=1,后面offset++即可)

后续任务

  1. 209和59的思路简单整理了下,等后面自己再亲自上手写写。

  1. 总结数组。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值