算法练习day2

226 阅读2分钟

一、有序数组的平方

问题要点

最直接的思路是数组每个元素平方,然后对数组排序即可,这个属于暴力解法

双指针的思路是这样:非递减数组的元素,平方后出现最大值的可能只在最左端(很小的负数,平方后的结果是很大的正数)或者最右端,所以对比左右两端的平方结果,放到对应的数组位置即可

暴力求解

时间复杂度是 O(nlogn)

/**
 * 暴力解法
 * @param {number[]} nums
 * @return {number[]}
 */
var sortedSquares = function(nums) {
    for(let i = 0; i < nums.length; i++) {
        nums[i] *= nums[i]
    }
    return nums.sort((x, y) => x - y)
};

双指针法

/**
 * 双指针法
 * @param {number[]} nums
 * @return {number[]}
 */
var sortedSquares = function(nums) {
    let result = []
    let k = nums.length - 1
    let left = 0
    let right = k
    while(left <= right) {
        if(nums[left] * nums[left] < nums[right] * nums[right]) {
            result[k--] = nums[right] * nums[right]
            right--
        } else {
            result[k--] = nums[left] * nums[left]
            left++
        }
    }
    return result
};

二、长度最小的子数组

问题要点

暴力求解的思路是双重循环,确定区间起点位置和区间终点位置,不断搜索区间获取并对比目标数据的过程

滑动窗口的思路,其实也是双指针的思路,但是更像是变化的窗口的移动 窗口的条件是满足值大于target,同时窗口起点要前进(窗口缩小)。从而更新目标结果 窗口的终点就是数组的索引

暴力求解

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

/**
 * 暴力求解
 * @param {number} target
 * @param {number[]} nums
 * @return {number}
 */
var minSubArrayLen = function(target, nums) {
    let res = Infinity
    let sum = 0
    let len = 0
    for(let i = 0; i < nums.length; i++) {
        sum = 0
        for(let j = i; j < nums.length; j++) {
            sum += nums[j]
            if(sum >= target) {
                len = j - i + 1
                res = len < res ? len : res
                break
            }
        }
    }
    return res === Infinity ? 0 : res
};

滑动窗口

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

/**
 * 滑动窗口
 * @param {number} target
 * @param {number[]} nums
 * @return {number}
 */
var minSubArrayLen = function(target, nums) {
    let res = Infinity
    let sum = 0
    let len = 0
    let left = 0
    let right = 0
    while(right < nums.length) {
        sum += nums[right]
        while(sum >= target) {
            res = Math.min(res, right - left + 1 )
            sum -= nums[left]
            left++
        }
        right++
    }
    return res === Infinity ? 0 : res
};

三、螺旋矩阵2

问题要点

旋转的方向要清晰,就是顺时针沿着矩阵遍历,一圈就是上面一行的从左到右,右边一列的从上到下,下面一行的从右到左,左边一列的从下到上

清晰所有的边界条件,一圈遍历完成后,更新各个边界条件,重复按照规则遍历

/**
 * @param {number} n
 * @return {number[][]}
 */
var generateMatrix = function (n) {
    let mid = Math.floor(n / 2)
    let loop = mid
    let count = 1
    let offset = 1
    let startRow = 0
    let startCol = 0
    let row = 0
    let col = 0
    let result = new Array(n).fill(0).map(_ => new Array(n).fill(0))
    while (loop--) {
        row = startRow
        col = startCol
        while (col < n - offset) {
            result[row][col] = count++;
            col++
        }
        while (row < n - offset) {
            result[row][col] = count++;
            row++
        }
        while (col > startCol) {
            result[row][col] = count++;
            col--
        }
        while (row > startRow) {
            result[row][col] = count++;
            row--
        }
        offset++
        startCol++
        startRow++
    }
    if (n % 2 !== 0) {
        result[mid][mid] = count
    }
    return result

};