59.螺旋矩阵Ⅱ

题目链接:https://leetcode.cn/problems/spiral-matrix-ii/

题目描述:

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

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

思路:

模拟题,需要按照顺序填充。仔细观察可以发现规律为:每次需要填充的元素列序号增加直到边界,行序号增加直到边界,列序号减小直到边界,行序号减小直到边界(向右,向下,向左,向上)。这里边界指的是超出数组范围和碰到已经填充的格子。可以使初始的答案矩阵matrix全部填充0,在之后的填充过程中如果碰到非零的元素说明到了边界。

代码:

/**
 * @param {number} n
 * @return {number[][]}
 */
 var generateMatrix = function(n) {
    let add = 1 //控制方向
    let i = 0 //行序号
    let j = 0 //列序号
    let t = 1 //填充的数
    let matrix = new Array(n).fill(0).map(()=>new Array(n).fill(0))

	//判断是否为边界
    const check = function(r,c){
        if(r < 0 || c < 0 || r >= n || c >= n || matrix[r][c] !== 0 ) return false
        return true
    }

    matrix[0][0] = 1
    while(t !== n * n ){
        while(check(i, j + add)){
            j += add
            t++
            matrix[i][j] = t         
        }
        while(check(i + add, j)){
            i += add
            t++
            matrix[i][j] = t            
        }
        add=-add
    }
     return matrix
};

977.有序数组的平方

题目链接:https://leetcode.cn/problems/squares-of-a-sorted-array/

题目描述:

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

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

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

思路:

双指针,先找到原数组中平方最小的元素,从它开始,向左和向右按照平方大小顺序逐步把元素的平方添加进结果数组中。

代码:

/**
 * @param {number[]} nums
 * @return {number[]}
 */
 var sortedSquares = function(nums) {
    let len = nums.length
    let middleIndex = 0 //平方最小元素的坐标
    let tmp = Math.pow(nums[0],2)
    
    //找到平方最小的元素,顺便在寻找过程中将原数组中的元素平方
    for(let i =0; i < len; i++){
        nums[i] = Math.pow(nums[i],2)
        if(tmp > nums[i]){
            tmp = nums[i]
            middleIndex = i
        }
    }
    let left = middleIndex - 1 //向左遍历
    let right = middleIndex + 1 //向右遍历
    let ansIndex = 0 //在结果数组中的下标
    let ans = new Array(len)
    ans[ansIndex++] = nums[middleIndex]
    while(left >= 0 && right < len){
        if(nums[left]>nums[right]){
            ans[ansIndex++] = nums[right++]
        }
        else if(nums[left] < nums[right]){
            ans[ansIndex++] = nums[left--]        
        }
        else{
           ans[ansIndex++] = nums[left--]
           ans[ansIndex++] = nums[right++]
        }
    }
    while(left >= 0){
        ans[ansIndex++] = nums[left--]
    }
    while(right < len){
        ans[ansIndex++] = nums[right++]
    }

    return ans

};

改进:

从原数组两边向中间遍历,从大到小的顺序将元素的平方从后往前放进结果数组中,从而避免了寻找最小平方的元素

209.长度最小的子数组

题目链接:

https://leetcode.cn/problems/minimum-size-subarray-sum/

题目描述:

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

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

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

输入:target = 4, nums = [1,4,4]
输出:1

输入:target = 11, nums = [1,1,1,1,1,1,1,1]
输出:0

思路:

最直接的思路是两层循环暴力求解,但是暴力求解明显重复考虑了一些情况,例如:如果一个子数组和比target大,那么包裹它的数组之和一定比target大。

改进的方法是采用滑动窗口的方式进行求解。从下标为零处开始,维护两个指针start和end,表示子数组头和尾的下标。

开始时start, end 均为0,end首先+1,使子数组变长,计算此时的数组和。如果比target小,说明以end结尾的子数组均不符合条件;如果比target大,则将start+1,使数组变短,计算此时的数组和,如果还大则继续缩短直到小于等于target,若等于保存此时的长度,若小于说明以end结尾的子数组均不符合条件。

重复上述过程将end从0遍历到原数组末尾,返回最小的长度。

代码:

/**
 * @param {number} target
 * @param {number[]} nums
 * @return {number}
 */
var minSubArrayLen = function(target, nums) {
    let start, end
    start = end = 0
    let sum = 0
    let len = nums.length
    let ans = Infinity
    
    while(end < len){
        sum += nums[end];
        while (sum >= target) {
            ans = Math.min(ans, end - start + 1);
            sum -= nums[start];
            start++;
        }
        end++;
    }
    return ans === Infinity ? 0 : ans
};