力扣刷题day02|977有序数组的平方、209长度最小的子数组、59螺旋矩阵II

977. 有序数组的平方

力扣题目链接

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

示例 1: 输入:nums = [-4,-1,0,3,10] 输出:[0,1,9,16,100] 解释:平方后,数组变为 [16,1,0,9,100],排序后,数组变为 [0,1,9,16,100]

示例 2: 输入:nums = [-7,-3,2,3,11] 输出:[4,9,9,49,121]

思路

数组平方完后,数组平方的最大值就在数组的两端,不是最左边就是最右边(负数平方之后可能成为最大数),不可能是中间。

难点

在循环遍历数组时left<=right,如果是left<right的话,最终两个指针共同指向的那个元素不会进行排序操作

双指针法

核心就是两边同时开始找较大的值,找到了就把最大值扔进新的平方数组

  • 左指针:从左边nums[0]开始找与右边相比更大的平方数
  • 右指针:从右边nums[length-1]开始找与左边相比更大的平方数

判断如果右边平方数大于左边,那么左边不动,右指针移到下一位

判断如果左边平方数大于右边,那么右边不动,左指针移到下一位

public int[] sortedSquares(int[] nums) {
        // 定义左右指针
        int left;
        int right;
        // 定义新数组及新数组下标
        int result[] = new int[nums.length];
        int len = nums.length-1;
        // 遍历原数组
        for (left = 0, right = nums.length - 1; left <= right;){
            // 如果是left<right的话,最终两个指针共同指向的那个元素不会进行排序操作
            if (nums[left] * nums[left] < nums[right] * nums[right]){
                // 右边平方数大于左边
                result[len--] = nums[right] * nums[right];
                right--;
            }else {
                // 左边平方数大于右边
                result[len--] = nums[left] * nums[left];
                left++;
            }
        }
        return result;

    }

时间复杂度为O(n)

209. 长度最小的子数组

力扣题目链接

给定一个含有 n 个正整数的数组和一个正整数 target 。

找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, …, numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。

示例:

输入:s = 7, nums = [2,3,1,2,4,3] 输出:2 解释:子数组 [4,3] 是该条件下的长度最小的子数组。

思路

用一个滑动窗口框住要计算的数,数多了就让左窗口往前移,和小了就让右窗口往后移

滑动窗口是计算机语言中重要的算法之一,主要用于处理连续的数组数据或者字符串数据,常用来提取数据中的子数组或者子串。 滑动窗口就是不断的调节子序列的起始位置和终止位置,从而得出我们要想的结果

在暴力解法中,是一个for循环滑动窗口的起始位置,一个for循环为滑动窗口的终止位置,用两个for循环 完成了一个不断搜索区间的过程。

滑动窗口:只用一个for循环,那么这个循环的索引,一定是表示滑动窗口的终止位置

难点

在本题中实现滑动窗口,主要确定如下三点:

  • 窗口内是什么? 答:是满足其和 ≥ s 的长度最小的连续子数组
  • 如何移动窗口的起始位置? 答:如果当前窗口的值大于s了,窗口就要向前移动了(也就是该缩小了)
  • 如何移动窗口的结束位置? 答:窗口的结束位置就是遍历数组的指针,也就是for循环里的索引

完整代码:

public int minSubArrayLen(int target, int[] nums){
    // 定义滑动窗口的左右窗口(指针)
    int left = 0;
    int right;
    // 定义窗口内的和
    int sum =0;
    // 定义窗口内子串长度
    int SubArrayLen = 0;
    // 定义返回窗口大小为不可能取到的最大值
    int result = Integer.MAX_VALUE;
    // 右窗口遍历数组
    for (right = 0; right < nums.length; right++){
        sum += nums[right];
        while (sum >= target){
            // 计算此时窗口长度
            SubArrayLen = right - left + 1;
            // 判断此时的窗口长度是否为最小
            result = result < SubArrayLen ? result : SubArrayLen;
            // 减去左窗口看窗口内和是否还大于等于s
            sum -= nums[left++];
        }
    }
    // 如果此时的窗口大小还是初始设置的不可能取到的最大值,那么返回
    return result == Integer.MAX_VALUE ? 0 : result;
}
  • 补充:

Java的基本数据类型:整型:int , short, long, byte;浮点型: float, double;字符型: char;布尔型: boolean

java的引用数据类型:Byte、Short、Integer、Long、Float、Double、Character、Boolean

其中Integer.MAX_VALUE表示:int 数据类型的最大值,即:2147483647

Integer.MIN_VALUE表示:int 数据类型的最小值,即:-2147483648

定义不可能取到的最大值,使数组没有满足要求的窗口时可以返回0。

result < subLength ? result : subLength可以替换为Math.min(result, minLen)

  • 时间复杂度:O(n)

不要以为for里放一个while就以为是O(n^2), 主要是看每一个元素被操作的次数,每个元素在滑动窗后进来操作一次,出去操作一次,每个元素都是被操作两次,所以时间复杂度是 2 × n 也就是O(n)。

59. 螺旋矩阵II

力扣题目链接

给你一个正整数 n ,生成一个包含 1n2 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix

示例1:

输入:n = 3
输出:[[1,2,3],[8,9,4],[7,6,5]]

示例 2:

输入:n = 1
输出:[[1]]

思路

模拟顺时针画矩阵的过程,利用左闭右开区间,打印完整个序列,即每一个拐角处的处理规则,拐角处让给新的一条边来继续画,若n为奇数中心点单独填充

难点

为什么loop的循环终止条件是< n / 2因为搜索一圈之后,下一圈的上边会往下走,下一圈的下边会往上走,高度就少2,下一圈的左边会往右走,下一圈的右边会往左走,相当于宽少2了,每次下一圈都会比上一圈的高度宽度都少2,直到这个没有外圈了,没有外圈就是宽度是和高度都是0的时候(偶数的情况),每次宽,高缩小2,直到宽,高是0。因为宽,高都一样,而且是一起缩2的,那么就当高缩2到0的时候就结束了,要缩多少次,就是圈。高假设是偶数,偶数-2-2-2一直到0,不就是这个偶数除2吗,就是圈数啦。

模拟顺时针画矩阵的过程:

  • 填充上行从左到右
  • 填充右列从上到下
  • 填充下行从右到左
  • 填充左列从下到上

完整代码

public int[][] generateMatrix(int n) {
    // 定义循环次数,若n为基数需要单独处理中间位置
    int loop = 0;
    // 定义起始位置,因为起始点的横纵坐标一定相等(n, n)
    int start = 0; //循环开始原点
    // 坐标常用表示为(i, j) ,因此这里i不动用j横向遍历,j不懂用i纵向遍历
    int i,j;
    // 定义矩阵大小
    int nums[][] = new int[n][n];
    // 定义填充数字,从1 ~ n*n
    int count = 1;
    // 矩阵每转一圈,下一次的坐标都要往内收offset
    int offset = 1;
    // 循环次数从0开始小于n/2
    while (loop < n >> 1){
        //上边从左到右
        for (j = start; j < n - offset; j++){
            // 左开右闭,用小于号使最右的值被右列处理
            nums[start][j] = count++;
        }
        //右边从上到下
        for (i = start; i < n - offset; i++){
            // 左开右闭,用小于号使最下的值被下边处理
            nums[i][j] = count++;
        }
        //下边从右往坐
        for ( ;j > start; j--){
            // 左开右闭,用小于号使最左的值被左列处理
            nums[i][j] = count++;
        }
        //左边从下往上
        for ( ;i > start; i--){
            nums[i][j] = count++;
        }
        // 初始位置横纵坐标都加1
        start++;
        // 往内收一圈
        offset++;
        loop++;
    }
    if (n % 2 == 1){
        nums[n >> 1][n >> 1] = count;
    }
    return nums;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值