算法day02-数组篇(2)
目录
- 209.长度最小的子数组(滑动窗口)
- 力扣100:无重复字符的最长子串
- 力扣100:找到字符串中所有字母异位词
- 59.螺旋矩阵
- 华为真题螺旋矩阵:
- 73题矩阵置零:
- 48题旋转图像:
- 240题搜索二维矩阵II:
- 区间和(前缀和):
- 开发商购买土地(二维前缀和):
一、长度最小的子数组
力扣209题长度最小的子数组,这一题209. 长度最小的子数组 - 力扣(LeetCode)。主要是考察对滑动窗口的理解。
class Solution { public int minSubArrayLen(int target, int[] nums) { int left = 0; int sum = 0; int minLength = Integer.MAX_VALUE; for(int right = 0; right < nums.length; right++){ sum += nums[right]; while(sum >= target){ //不断缩小窗口但满足条件,直到得到一个最小的值 minLength = Math.min(minLength, right - left + 1); sum -= nums[left]; left++; } } return minLength == Integer.MAX_VALUE ? 0 : minLength; } }
//时间复杂度:O(n),最多执行2n次操作
//空间复杂度:O(1),没有额外数组
【相关题目】
- 3题无重复字符的最长子串:https://leetcode.cn/problems/longest-substring-without-repeating-characters/description/?envType=study-plan-v2&envId=top-100-liked
- 438题找到字符串中所有字母异位词:https://leetcode.cn/problems/find-all-anagrams-in-a-string/description/?envType=study-plan-v2&envId=top-100-liked
二、螺旋矩阵II
主要思路:就是定义四个指针,上下左右,重点在判断是否到达边界,然后按照图示的顺序来进行遍历。
class Solution { public int[][] generateMatrix(int n) { int left = 0,right = n-1; int top = 0, bottom = n-1; int[][] nums = new int[n][n]; int a = 1; while(left <= right && top <= bottom){ for(int i=left; i<=right; i++){ nums[top][i] = a; a++; } top++; for(int i=top; i<=bottom; i++){ nums[i][right] = a; a++; } right--; if(top <= bottom){ for(int i=right; i>=left; i--){ nums[bottom][i] = a; a++; } bottom--; } if(left <= right){ for(int i=bottom; i>=top; i--){ nums[i][left] = a; a++; } left++; } } return nums; } }
//时间复杂度:O(n^2)
//空间复杂度:O(n^2)
【矩阵相关题目】
- 华为真题螺旋矩阵:
- 73题矩阵置零:
- 48题旋转图像:
- 240题搜索二维矩阵II:
三、区间和(前缀和)
import java.util.Scanner; public class Main{ public static void main(String[] args){ Scanner in = new Scanner(System.in); int n = in.nextInt(); int[] nums = new int[n]; for(int i=0; i<n; i++){ nums[i] = in.nextInt(); } int[] preSum = new int[n+1]; for(int i=0; i<n; i++){ //注意这里不是n-1 preSum[i+1] = preSum[i] + nums[i]; } in.nextLine(); while(in.hasNext()){ String[] parts = in.nextLine().trim().split("\\s+"); int num1 = Integer.parseInt(parts[0]); int num2 = Integer.parseInt(parts[1]); System.out.println(preSum[num2+1] - preSum[num1]); } } }
//时间复杂度:O(N),构造前缀和O(N),每次查询O(1)
//空间复杂度:O(N),nums和preSum
四、开发商购买土地【有难度】
主要思路:构建二维矩阵的前缀和。然后分横向和纵向讨论两种切法得到的sum。
import java.util.*; import java.lang.*; public class Main{ public static void main(String[] args){ Scanner in = new Scanner(System.in); int n = in.nextInt(); int m = in.nextInt(); int[][] nums = new int[n][m]; //读入矩阵 for(int i=0; i<n; i++){ for(int j=0; j<m; j++){ nums[i][j] = in.nextInt(); } } //计算行和列的前缀和 int[][] preSum = new int[n+1][m+1]; for(int i=0; i<n; i++){ for(int j=0; j<m; j++){ //这里可以画图理解,前两者-重叠部分+最右下角元素 preSum[i+1][j+1] = preSum[i][j+1] + preSum[i+1][j] - preSum[i][j] + nums[i][j]; } } int total = preSum[n][m]; int minDiff = Integer.MAX_VALUE; //横向划分 for(int rowCut = 1; rowCut < n ; rowCut++){ int Asum = getSum(preSum, 0, 0, rowCut-1, m-1); int Bsum = total - Asum; minDiff = Math.min(minDiff, Math.abs(Asum-Bsum)); } //纵向划分 for(int colCut = 1; colCut < m; colCut++){ int Asum = getSum(preSum, 0, 0, n-1, colCut-1); int Bsum = total - Asum; minDiff = Math.min(minDiff, Math.abs(Asum-Bsum)); } System.out.println(minDiff); } // 获取区域 [r1, c1] ~ [r2, c2] 的总和 public static int getSum(int[][] preSum, int r1, int c1, int r2, int c2){ return preSum[r2+1][c2+1] - preSum[r1][c2+1] - preSum[r2+1][c1] + preSum[r1][c1]; } }
//时间复杂度:O(N+M)
//空间复杂度:O(N+M)