算法训练第二天| 209.长度最小的子数组| 59.螺旋矩阵II

LeetCode 209.长度最小的子数组

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

题目讲解:代码随想录

题目描述:给定一个含有 n 个正整数的数组和一个正整数 target 。找出该数组中满足其总和大于等于 target 的长度最小的 子数组[numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度如果不存在符合条件的子数组,返回 0 。

使用滑动窗口比较合适,所谓滑动窗口,就是不断的调节子序列的起始位置和终点位置,从而得出我们要想的结果。在暴力解法中,是一个for循环滑动窗口的起始位置,一个for循环为滑动窗口的终止位置,用两个for循环 完成了一个不断搜索区间的过程。

滑动窗口可以使用一个for循环来解决暴力解法中的双for循环,但是要考虑滑动窗口中的for循环是作为窗口的起始位置还是终点位置。

假设把滑动窗口中的for循环作为起始位置,当每次确认窗口大小时,终点指针必须要遍历一遍数组,这样做和暴力解法没有区别。故应该把滑动窗口中的for循环作为窗口的终点位置

// 时间复杂度:O(n)
// 空间复杂度:O(1)
func minSubArrayLen(target int, nums []int) int {
    i := 0 // 代表滑动窗口的起始位置
    l := len(nums)
    sum := 0
    result := l + 1
    for j := 0; j < l; j++{ // j代表滑动窗口的结束位置
        sum += nums[j] // 累加滑动窗口内的值
        for sum >= target{  
            subLength := j - i + 1
            if subLength < result{
                result = subLength // 拿到最小符合题目要求的长度
            }
            sum -= nums[i] // 剔除窗口初始位置的值
            i++
        }
    }

    if result == l + 1{
        return 0
    }else{
        return result
    }
}
  • 其中result代表的是最终最短的满足条件的长度,设置初始化的时候要比数组长度大,比如,len(nums)+1
  • for sum >= target,这里一定要使用for,不能使用if。比如,数组为[1,1,1,1,1,1005],要找出满足其和大于等于1005的最小长度。当终点位置指针指向1005时,初始位置指针要逐步向后移动。

 LeetCode 59.螺旋矩阵II

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

题目讲解:代码随想录

题目描述:给你一个正整数 n ,生成一个包含 1 到 n^{2}所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。

// 时间复杂度 O(n^2): 模拟遍历二维矩阵的时间
// 空间复杂度 O(1)
func generateMatrix(n int) [][]int {
    startx, starty := 0, 0
    var loop int = n / 2      // 循环的次数
    var center int = n / 2    // 如果n为奇数,则需要单独设置中心位置的值
    count := 1                // 要给矩阵赋的值
    offset := 1               // 采用左闭右开时,设置的偏移值

    res := make([][]int, n)       // 初始化二维切片,每一个元素都是长度为n的切片
    for i := 0; i < n; i++ {
		res[i] = make([]int, n)   // 初始化一维切片,每一行都是长度为n的切片
	}

    for loop > 0{
        i, j := startx, starty

        // 行数不变,列在变
        for j = starty; j < n - offset; j++{
            res[startx][j] = count
            count++
        }

        // 列数不变为j,行数变
        for i = startx; i < n - offset; i++{
            res[i][j] = count
            count++
        }

        // 行数不变为i,列数变
        for ; j > starty;j--{
            res[i][j] = count
            count++
        }

        // 列数不变为j,行变
        for ; i > startx; i--{
            res[i][j] = count
            count++
        }

        startx++
        starty++
        offset++
        loop--
    }
    if n%2 == 1{
        res[center][center] = n * n
    }
    return res
}

 kamaCoder 58.区间和

题目链接:58.区间和

题目讲解:代码随想录

题目描述:给定一个整数数组 Array,请计算该数组在每个指定区间内元素的总和。

输入描述:第一行输入为整数数组 Array 的长度 n,接下来 n 行,每行一个整数,表示数组的元素。随后的输入为需要计算总和的区间下标:a,b (b > = a),直至文件结束。

输出描述:输出每个指定区间内元素的总和。

推荐使用前缀和的方式来做,其思想是重复利用计算过的子数组之和,从而降低区间查询需要累加计算的次数

例如,我们要统计vec[i] 这个数组上的区间和。我们先做累加,即 p[i] 表示下标 0 到 i 的 vec[i]累加之和。如果,我们想统计,在vec数组上下标 2 到下标 5 之间的累加和,就用 p[5] - p[1] 就可以了。

p[1] = vec[0] + vec[1];

p[5] = vec[0] + vec[1] + vec[2] + vec[3] + vec[4] + vec[5];

p[5] - p[1] = vec[2] + vec[3] + vec[4] + vec[5];

package main

import (
    "bufio"
    "fmt"
    "os"
    "strconv"
)

func calculateRangeSum(array []int, start, end int) int {
    prefixSumStart := 0
    if start > 0 {
        prefixSumStart = array[start-1]
    }
    return array[end] - prefixSumStart
}


func main() {
    scanner := bufio.NewScanner(os.Stdin)

    // 读取数组大小
    scanner.Scan()
    size, _ := strconv.Atoi(scanner.Text())

    // 读取数组元素
    numberArray := make([]int, size)
    for i := 0; i < size; i++ {
        scanner.Scan()
        numberArray[i], _ = strconv.Atoi(scanner.Text())
    }

    // 计算前缀和数组
    prefixArray := make([]int, size)
    prefixArray[0] = numberArray[0]
    for i := 1; i < size; i++ {
        prefixArray[i] = prefixArray[i-1] + numberArray[i]
    }

    // 计算区间和
    for scanner.Scan() {
        line := scanner.Text()
        fields := []int{0, 0}
        _, err := fmt.Sscanf(line, "%d %d", &fields[0], &fields[1])
        if err != nil {
            continue
        }

        if fields[0] < 0 || fields[1] >= size {
            continue
        }
        fmt.Println(calculateRangeSum(prefixArray, fields[0], fields[1]))
    }
}

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值