第一章 数组Part2
209.长度最小的子串
思路:
使用滑动窗口,i指向长度最小子数组的开始位置,j指向长度最小子数组的结束位置。
j先右移,当子数组和大于target时,j停止移动,i右移,直到子数组和小于target。
class Solution {
public int minSubArrayLen(int target, int[] nums) {
//滑动窗口
//i指向长度最小子数组的开始位置,j指向长度最小子数组的结束位置
//j先右移,当子数组和大于target时,j停止移动,i右移,直到子数组和小于target
int i = 0, j = 0;
int sum = 0, sumLength = Integer.MAX_VALUE;
for(j = 0; j < nums.length; j++){
sum += nums[j];
while(sum >= target){
//左右边界异动后都要更新长度
sumLength = (j - i + 1) < sumLength ? (j - i + 1) : sumLength;
sum -= nums[i++];
}
}
return sumLength == Integer.MAX_VALUE ? 0 : sumLength;
}
}
反思:
1.对循环条件的考虑不到位。看了思路后自己先写,两层循环写了外层循环控制开始位置。
2.子数组长度的更新在循环外。每次边界变化后子数组的长度都应该随之变化。
59.螺旋矩阵Ⅱ
思路:
先写出最外面一圈,然后找到控制移动的变量。
使用左闭右开的原则,从左到右-从上到下-从右到左-从下到上。
一圈结束后,下标缩小,start++,end--.
class Solution {
public int[][] generateMatrix(int n) {
int[][] matrixs = new int[n][n];
int count = 1;
int start = 0;int end = n;
int row = 0, col = 0;
while(end > 1){
for(col = start; col < end - 1; col++){
matrixs[start][col] = count++;
}
for(row = start; row < end - 1; row++){
matrixs[row][end - 1] = count++;
}
for(col = end - 1; col > start; col--){
matrixs[end - 1][col] = count++;
}
for(row = end - 1; row > start;row--){
matrixs[row][start] = count++;
}
start++;
end--;
}
if(n % 2 != 0){//奇数最中心的数
matrixs[n / 2][n / 2] = n * n;
}
return matrixs;
}
}
58. 区间和
思路:
采用for循环不断累加区间和会造成超时。
计算前缀和即下标0到下标i的和,区间[a,b]的区间和=前缀和[b]-前缀和[a-1]
import java.util.Scanner;
public class Main {
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] arr1 = new int[n];
int[] sumRange = new int[n];
int preSum = 0;
for(int i = 0; i < n; i++){
arr1[i] = sc.nextInt();
preSum += arr1[i];
sumRange[i] = preSum;
}
while(sc.hasNextInt()){
int a = sc.nextInt();
int b = sc.nextInt();
int sum = 0;
if(a == 0){
sum = sumRange[b];
}else{
sum = sumRange[b] - sumRange[a - 1];
}
System.out.println(sum);
}
sc.close();
}
}
反思:
不熟悉acm模式是做这道题最大的问题
44.开发商购买土地
思路:
前缀和暴力解法
import java.util.Scanner;
public class Main{
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int m = sc.nextInt();
int[][] area = new int[n][m];
int sum = 0;
//录入每块地的权值,并对权值求和
for(int i = 0; i < n; i++){
for(int j = 0; j < m; j++){
area[i][j] = sc.nextInt();
sum += area[i][j];
}
}
//记录最小总价值差
int minCut = Integer.MAX_VALUE;
//每行求和
int[] rowSum = new int[n];
for(int i = 0; i < n; i++){
for(int j = 0; j < m; j++){
rowSum[i] += area[i][j];
}
}
//每列求和
int[] colSum = new int[m];
for(int i = 0; i < m; i++){
for(int j = 0; j < n; j++){
colSum[i] += area[j][i];
}
}
//求横向划分的最小差
int rowCut = 0;
for(int i = 0; i < n; i++){
rowCut += rowSum[i];
//减2*Math.abs(sum - 2 * rowCut),是求出剩余区域的权值和后求总价值之差
minCut = minCut < Math.abs(sum - 2 * rowCut) ? minCut : Math.abs(sum - 2 * rowCut);
}
//求纵向划分的最小差
int colCut = 0;
for(int j = 0; j < m; j++){
colCut += colSum[j];
minCut = minCut < Math.abs(sum - 2 * colCut) ? minCut : Math.abs(sum - 2 * colCut);
}
System.out.println(minCut);
sc.close();
}
}
优化思路:
在横向和纵向遍历的时候,每遍历到行/列尾,与最小差比较,若小于就更新。
import java.util.Scanner;
public class Main{
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int m = sc.nextInt();
int sum = 0;
int[][] area = new int[n][m];
for(int i = 0;i < n;i++){
for(int j = 0;j < m; j++){
area[i][j]= sc.nextInt();
sum += area[i][j];
}
}
int minCut = Integer.MAX_VALUE;
int rowSum = 0;
for(int i = 0;i < n;i++){
for(int j = 0;j < m; j++){
rowSum += area[i][j];
if(j == m - 1){
minCut = minCut < Math.abs(sum - 2 * rowSum) ? minCut : Math.abs(sum - 2 * rowSum);
}
}
}
int colSum = 0;
for(int i = 0;i < m;i++){
for(int j = 0;j < n; j++){
colSum += area[j][i];
if(j == n - 1){
minCut = minCut < Math.abs(sum - 2 * colSum) ? minCut : Math.abs(sum - 2 * colSum);
}
}
}
System.out.println(minCut);
sc.close();
}
}

浙公网安备 33010602011771号