[代码随想录]Day02-数组part02

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

思路:

一开始的思路是从中间向两边扩:

  1. 找到第一个大于等于0的位置r;判断nums[r]是否大于等于0,如果不是赋值为len(nums)表示不在范围内了。
  2. l的位置在r的左侧因此l = r - 1
  3. 只要l>=0或者r<len(nums)满足一个就可以继续;遍历时要保证数组不能越界

说实话维护起来有些复杂了,但是逆向思考一下,既然可以从中间向两边扩那是否可以从两边向中间缩?当然可以!

  1. l初始位置0,r初始位置len(nums)
  2. 每次判断l和r位置上的数谁更大,放在结果数组的尾部即可。

代码1:

从两边向中间缩

func sortedSquares(nums []int) []int {
    lens := len(nums)
    res := make([]int,lens) // 结果长度为lens
    l, r := 0, lens-1
    for i := lens - 1; i >= 0 ; i-- { // 逆序
        a, b := nums[l]*nums[l], nums[r]*nums[r]
        if a > b { // 大的放在后面
            res[i] = a
            l++
        }else {
            res[i] = b
            r--
        }
    }
    return res
}

代码2:

从中间向两边扩

func sortedSquares(nums []int) []int {
    l, r := 0, 0
    lens := len(nums)
    res := []int{}
    for i:=0 ; i < lens; i++ {  // 找到第一个大于等于0的位置
        if nums[i] >= 0 {
            r  = i
            break
        }
    }
    if nums[r] < 0 { // 如果nums[r] < 0 说明全是负数
        r = lens
    }
    l = r - 1 // l在r的左侧开始
    for l >= 0 || r < lens { // 只要有一个满足就可以继续
        if l == -1 {
            res = append(res, nums[r] * nums[r])
            r++
        }else if r == lens{
            res = append(res, nums[l] * nums[l])
            l--
        }else if -nums[l] < nums[r] { // 正序找小的放在前面
            res = append(res, nums[l] * nums[l])
            l--
        }else {
            res = append(res, nums[r] * nums[r])
            r++
        }
    }
    return res
}

参考:

文章讲解

视频讲解

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

思路:

209.长度最小的子数组

滑动窗口说白了就是高级版的双指针法,滑动窗口无非就是双指针的同时还要维护两个指针中间部分元素的某个特定条件,比如本题是两个指针中间的元素和。

本题的几个要点:

  1. l和r都是从0开始出发
  2. 如果滑动窗口内元素和小于target右指针向右(如果左指针向右只会变得更小)
  3. 如果滑动窗口内元素和大于等于target左指针向右,直到不再满足该条件

因为题目要找的是最少元素,因此当滑动窗口内元素和第一次大于等于target时再向右移动右指针就没有意义了;此时向右移动左指针看是否可以减少元素的同时满足条件。

代码:

滑动窗口

func minSubArrayLen(target int, nums []int) int {
    l := 0
    sum := 0
    res := 1000000 // 长度
    for r := 0 ; r <len(nums); r++ { // 遍历右窗口
        sum += nums[r]
        for sum >= target { // 左窗口向右
            res = min(res, r - l + 1)
            sum -= nums[l]
            l++
        }
    }
    if res == 1000000 {
        return 0
    }
    return res
}

func min(a,b int) int { // 返回较小的值
    if a < b {
        return a
    }
    return b
}

参考:

文章讲解

视频讲解

题目:59. 螺旋矩阵 II

思路:

把矩阵看成多个圆,每次遍历一个圆,遍历一次的过程是:

image-20230727221857056

  1. top上部,从left遍历到right
  2. right右侧,从top-1遍历到bottom
  3. bottom下部,从right-1遍历left
  4. left左侧,从bottom+1遍历到top-1

之后就是分治思想每次重复上述步骤就行了;当只剩下一行或者一列的时候就不要继续四次遍历了,两次即可。比如上面图两次遍历上、右就完成了填充,如果四次遍历的话第三次的遍历(绿色)会覆盖掉第一次遍历的结果(红色),所以这里加了一个if判定。

代码:

func generateMatrix(n int) [][]int {
    res := make([][]int,n) // 行数row
    for i := range res {
        res[i] = make([]int,n) // 列数col
    }
    left,right,top,bottom := 0, n-1, 0, n-1 // 初始的边界
    cnt := 1 
    for left <= right && top <= bottom {
        for col := left ; col <= right; col ++ {
            res[top][col] = cnt
            cnt++
        } // 填充上部
        for row := top + 1; row <= bottom; row ++ {
            res[row][right] = cnt
            cnt++
        }// 填充右侧
        if left < right && top < bottom { // 在长宽不相等的情况下,如果只剩下一行或者一列只需要上面两步即可完成。
            for col := right - 1; col >= left; col-- {
                res[bottom][col] = cnt
                cnt++
            }// 填充下部
            for row := bottom - 1; row > top; row-- {
                res[row][left] = cnt
                cnt++
            }// 填充左侧
        }
        // 边界向中心靠
        left++ 
        right--
        top++
        bottom--
    }
    return res
}

参考:

文章讲解

视频讲解

posted @   WtcSky  阅读(7)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
点击右上角即可分享
微信分享提示