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

977.有序数组的平方

题目链接: 977. 有序数组的平方

参考文章链接:代码随想录_977. 有序数组的平方

  • 个人思考层面

在拿到题目时,会因为给出的数组有序这一条件,在思考如何利用,或是根据这个条件能够得到时间复杂度较低的算法,反而忽视了可以直接排序这种方式,而其他方法也没有很好的实现,就走上了一条尝试自己造出比已有算法耗时更低的算法的死胡同(一方面是对语言的不熟悉,另一方面也是没怎么做过题的原因,脑子里一直没有闪现过排序算法的想法)。另一点问题,没能意识到题目未对空间进行限制,解题时未想到新造数组,这是读题方面的失误。

  • 解题思路

方式一:如果不追求更低的时间复杂度,这题其实较为容易解决,只需要在将数组元素平方后,调用sort函数对数组元素进行排序,就能得到想要的结果,或是也可手动实现快排等排序算法,时间复杂度保持在 O ( n + l o g n ) O(n + logn) O(n+logn)

代码如下:

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

方式二:再利用到上述所提到的原数组有序的条件,因为数组可能存在负数的原因,平方后的元素从两边至中间大小是递减的,只需要想到可以新建一个空数组,原数组中用leftright两个指针分别指向起始和终止位置,并比较大小,较大的那个复制到新数组中(从后往前填放),然后该指针前移。不断重复这一步骤,填满元素的新数组就是目标值。

代码如下:

class Solution {
    public int[] sortedSquares(int[] nums) {
        int left = 0, right = nums.length - 1;
        //分别指向原数组的起始和终止位置
        int[] result = new int[nums.length];
        int index = result.length - 1;
        //指向新数组的终止位置
        while (left <= right) {
        //如果 left > right,说明数组元素已经遍历完,跳出循环
            if (nums[left] * nums[left] >= nums[right] * nums[right]) {
            //将较大的元素复制到新数组的索引值较大的位置,从而新数组实现从小到大排序
                result[index--] = nums[left] * nums[left];
                left++;
            } else {
                result[index--] = nums[right] * nums[right];
                right--;
            }
        }
        return result;
    }
}

209.长度最小的子数组

题目链接:209.长度最小的子数组

参考文章链接:代码随想录_209.长度最小的子数组

  • 个人思考层面

根据题目的描述,很容易能想到暴力解法,两层循环,外层进行限定连续子数组中的起始位置,内层限定结束位置,找到原数组中每个元素为始的连续子数组长度,记录并取最小值。
(虽然力扣更新了数据后,暴力解法变得超时了)

代码如下:

class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        //申请一个新数组,对原数组遍历,新数组中对应位置存储,需要多少个加起来才能大于等于target
        //事实上可以不需要新数组的加入,只是每次记录最小的那个值并保存即可,可节省空间,但时间复杂度不变
        int len = nums.length;
        int[] arr = new int[len];
        for (int i = 0; i < len; i++) {
            int sum = 0;
            for (int j = i; j < len; j++) {
                sum += nums[j];
                if (sum >= target) {
                    arr[i] = j - i + 1;
                    break;
                }
            }
        }
        int minIndex = 0;
        for (int i = 0; i < len; i++) {
            if (arr[i] < arr[minIndex] && arr[i] != 0)
                minIndex = i;
        }
        return arr[minIndex];
    }
}
  • 滑动窗口

更好的做法是利用滑动窗口的思想,能够在 O ( n ) O(n) O(n)的时间复杂度内完成问题的求解。其主要思想是用一个循环只记录该华东窗口的终止位置,实现长度最小子数组的查找。如果当前窗口内的元素和大于等于val,那个窗口的起始位置就要向后移动(窗口缩小);窗口内元素和小于val,窗口的终止位置向后移动,即循环里的索引向后移动(窗口增大)

代码如下:

class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int left = 0;
        int result = Integer.MAX_VALUE;
        //初值设定为整形最大值
        int sum = 0;
        for (int right = 0; right < nums.length; right++) {
        //窗口的右指针
            sum += nums[right];
            //计算窗口内的元素和
            while (sum >= target) {
                result = Math.min(result, right - left + 1);
                sum -= nums[left++];
                //窗口的左指针右移
            }
        }

        return result == Integer.MAX_VALUE ? 0 : result;
        //判断是否不存在符合条件的子数组
    }
}

59.螺旋矩阵II

题目链接:59.螺旋矩阵II

题解链接:lc题解

个人觉得过于复杂,看到题目后没什么思路,边去查看了题解,觉得下面这种写法尤为优雅且简洁易操作。
最难的部分在于对边界的控制,这种解题思路中每一圈分上下左右进行操作,并分别用变量tblr 对上下左右进行限定。例如,上面一行从左至右进行遍历后,为防止后续元素重复令t += 1,相当于上边界向内缩1.

class Solution {
    public int[][] generateMatrix(int n) {
        int[][] res = new int[n][n];
        int l = 0, r = n - 1, t = 0, b = n - 1;
        //初始的四个边界位置
        int num = 1;
        int tar = n * n;
        while (num <= tar) {
            for (int i = l; i <= r; i++) res[t][i] = num++;
            t++;  
            for (int i = t; i <= b; i++) res[i][r] = num++;
            r--;
            for (int i = r; i >= l; i--) res[b][i] = num++;
            b--;
            for (int i = b; i >= t; i--) res[i][l] = num++;
            l++;
        }
        return res;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值