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 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]))
}
}