双指针:快慢指针、对撞指针、滑动窗口。相关博客:双指针算法详解(快慢指针、对撞指针、滑动窗口)
209.长度最小的子数组
题目:给定一个含有 n 个正整数的数组和一个正整数 target 。
找出该数组中满足其总和大于等于 target 的长度最小的
子数组
[numsl, numsl+1, …, numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。
重点:需要明白长度是在哪个指针移动的时候更新的。这个题目中最小子数组的长度是在慢指针移动的时候更新的。
思想:双指针思想,遍历fast指针,然后每次都判断一下当前子数组是否满足题目要求,如果满足就进入while循环。while循环是用来移动slow指针的位置的,先计算子数组长度判断是否对最小长度进行更新,然后更新slow指针的位置。
class Solution {
public int minSubArrayLen(int target, int[] nums) {
//开始有新的理解了
int sum = 0;
int ans = 0;
for(int slow = 0, fast = 0; fast < nums.length; fast++){
//其中j就是快指针
sum+=nums[fast];
while(sum >= target){
if(ans > fast-slow+1 || ans == 0 ){
ans = fast-slow+1;
}
sum -= nums[slow];
slow++;
}
}
return ans;
}
}
class Solution:
def minSubArrayLen(self, target: int, nums: List[int]) -> int:
slow = 0
ans = 0
numSum = 0
for fast in range(len(nums)):
numSum += nums[fast]
while(numSum >= target):
if(ans > fast-slow+1 or ans == 0):
ans = fast - slow +1
numSum -= nums[slow]
slow+=1
return ans
好像很多乍一看可以用两层for循环进行暴力求解的,都可以试试双指针。就是双指针的初始化的位置,移动的条件需要思考一下,这些是不同的。
59.螺旋矩阵II
题目:给你一个正整数 n ,生成一个包含 1 到 n2 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。
重点:循环不变量。区间定义。(是左闭右闭还是左闭右开,在循环中不要发生变化。)在这个螺旋数组中区间定义就是左闭右开。
思想:一次循环就是一圈,每一圈四个方向。这个循环和上一个循环之间的差异是什么,什么变化了。
class Solution {
public int[][] generateMatrix(int n) {
int count=1;
int offset = 1;
int startx = 0;
int starty = 0;
int i=0, j=0;
int[][] nums = new int[n][n];
for(int iter=0; iter <n/2;iter++){//转这些圈
for(j = starty; j < n-offset;j++){
nums[startx][j] = count++;
}
for(i = startx; i < n-offset; i++){
nums[i][j] = count++;
}
for(; j>starty;j--){
nums[i][j] = count++;
}
for(; i>startx;i--){
nums[i][j] = count++;
}
startx++;
starty++;
offset++;
}
if(n%2==1){
nums[n/2][n/2] = count;
}
return nums;
}
}
有很多人说就是这个不好的一点就是变量定义的太多,但是我感觉虽然变量定义多,看起来有点冗余,但是好理解。下面是我自己减少了变量后写的。
class Solution {
public int[][] generateMatrix(int n) {
int count = 1;
int i=0, j=0;
int[][] matrix = new int[n][n];
for(int circles=0; circles < n/2; circles++){
for(j=circles; j < n - circles-1; j++){
matrix[circles][j] = count++;
}
for(i=circles; i < n - circles-1; i++){
matrix[i][j] = count++;
}
for(; j > circles; j--){
matrix[i][j] = count++;
}
for(; i > circles; i--){
matrix[i][j] = count++;
}
}
if(n%2==1){
matrix[n/2][n/2] = count;
}
return matrix;
}
}
下面是python版本,感觉python由于while和for和JAVA,C++不同就得多思考一下,用for的话得思考清楚四个边角的坐标。
class Solution:
def generateMatrix(self, n: int) -> List[List[int]]:
count = 1
q = 0
i = 0
j = 0
matrix = [[0 for _ in range(n)] for _ in range(n)]
#转多少圈
while(q < n/2):
j = q
i = q
while(j < n-q-1):
matrix[i][j] = count
count+=1
j+=1
while(i < n-q-1):
matrix[i][j] = count
count+=1
i+=1
while(j > q):
matrix[i][j] = count
count+=1
j-=1
while(i > q):
matrix[i][j] = count
count+=1
i-=1
q += 1
if(n%2 == 1):
matrix[i][j] = count
return matrix
下面是代码随想录上的,我就粘贴一个了。
class Solution:
def generateMatrix(self, n: int) -> List[List[int]]:
nums = [[0] * n for _ in range(n)]
startx, starty = 0, 0 # 起始点
loop, mid = n // 2, n // 2 # 迭代次数、n为奇数时,矩阵的中心点
count = 1 # 计数
for offset in range(1, loop + 1) : # 每循环一层偏移量加1,偏移量从1开始
for i in range(starty, n - offset) : # 从左至右,左闭右开
nums[startx][i] = count
count += 1
for i in range(startx, n - offset) : # 从上至下
nums[i][n - offset] = count
count += 1
for i in range(n - offset, starty, -1) : # 从右至左
nums[n - offset][i] = count
count += 1
for i in range(n - offset, startx, -1) : # 从下至上
nums[i][starty] = count
count += 1
startx += 1 # 更新起始点
starty += 1
if n % 2 != 0 : # n为奇数时,填充中心点
nums[mid][mid] = count
return nums
区间和
题目描述:给定一个整数数组 Array,请计算该数组在每个指定区间内元素的总和。
重点:前缀和。
思想:遍历计算[0,i]的区间的和也就是前缀和,
i
∈
[
0
,
l
e
n
(
A
r
r
a
y
)
−
1
]
i \in[0,len(Array)-1]
i∈[0,len(Array)−1]。缀和数组的每个元素存储的是原数组从起始位置到当前位置所有元素的累积和。在输入不同的区间的时候,只需要查询前缀和数组中相应的下标然后进行输出或者减法计算即可。
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int[] vec = new int[n];
int[] p = new int[n];
int presum = 0;
for (int i = 0; i < n; i++) {
vec[i] = scanner.nextInt();
presum += vec[i];
p[i] = presum;
}
while (scanner.hasNextInt()) {
int a = scanner.nextInt();
int b = scanner.nextInt();
int sum;
if (a == 0) {
sum = p[b];
} else {
sum = p[b] - p[a - 1];
}
System.out.println(sum);
}
scanner.close();
}
}
import sys
input = sys.stdin.read
def main():
data = input().split()
index = 0
n = int(data[index])
index += 1
vec = []
for i in range(n):
vec.append(int(data[index + i]))
index += n
p = [0] * n
presum = 0
for i in range(n):
presum += vec[i]
p[i] = presum
results = []
while index < len(data):
a = int(data[index])
b = int(data[index + 1])
index += 2
if a == 0:
sum_value = p[b]
else:
sum_value = p[b] - p[a - 1]
results.append(sum_value)
for result in results:
print(result)
if __name__ == "__main__":
main()
开发商购买土地
重点:前缀和。
数组总结
关键:区间定义(循环不变量)和双指针。
基础:数组定义,存储。
相关的题目、视频和文章
- https://leetcode.cn/problems/minimum-size-subarray-sum/
- https://programmercarl.com/0209.%E9%95%BF%E5%BA%A6%E6%9C%80%E5%B0%8F%E7%9A%84%E5%AD%90%E6%95%B0%E7%BB%84.html
- https://www.bilibili.com/video/BV1tZ4y1q7XE/
- https://leetcode.cn/problems/spiral-matrix-ii/
- https://programmercarl.com/0059.%E8%9E%BA%E6%97%8B%E7%9F%A9%E9%98%B5II.html
- https://www.bilibili.com/video/BV1SL4y1N7mV/
- https://www.programmercarl.com/kamacoder/0058.%E5%8C%BA%E9%97%B4%E5%92%8C.html
- https://www.programmercarl.com/kamacoder/0044.%E5%BC%80%E5%8F%91%E5%95%86%E8%B4%AD%E4%B9%B0%E5%9C%9F%E5%9C%B0.html
- https://programmercarl.com/%E6%95%B0%E7%BB%84%E6%80%BB%E7%BB%93%E7%AF%87.html