209.长度最小的子数组
思路:穷举数组中所有的子数组,然后求和与目标值比较
方法:暴力、滑动窗口
代码实现:
//1、定义初始变量
int left = 0; //起始位置
int sum = 0; //滑动窗口内的元素和
int result = Integer.MAX_VALUE; //满足条件数组的最小长度
//2、循环遍历数组,获得满足条件的最小数组
for (int right = 0; right < nums.length; right++) {
sum += nums[right]; //窗口内元素的和
//窗口内的和满足目标值
if (sum >= target){
//1、获取 最小数组长度
result = Math.min(result,right-left+1);
//2、窗口内的和 改变
sum -= nums[left];
//3、起始位置 改变
left++;
}
}
//3、返回数据
return result == Integer.MAX_VALUE ? 0 : result;
Tips:
暴力求解需要两层for循环,时间复杂度O(n²);
滑动窗口使用一个for循环比遍历所有的元素,区间开始位置的指针不再使用循环来表示,
时间复杂度为O(n).
59.螺旋矩阵II
思路:模拟顺时针画矩阵的过程:填充数据时:上边从左到右,右边从上到下,下边从右到左,左边从下到上。
//1、初始化变量
int[][] nums = new int[n][n]; //输出的数组
int startX = 0, startY = 0; // 每一圈的起始点
int offset = 1; //偏移量
int count = 1; //填充的数字
int loop = 1; //记录当前圈数
int i, j; //i代表行,j代表列
//2、转圈
while (loop <= n / 2) {
//上边:从原点开始,列j改变.遵循左闭右开原则,列不对第一行的最后一个位置元素值操作 j=n-offset
for (j = startY; j < n - offset; j++) {
nums[startX][j] = count;
count++;
}
//右边:行i改变,列j值不变(j=n-offset).遵循左闭右开原则,行不对右边最后一个元素操作 i= n-offset
for (i = startX; i < n - offset; i++) {
nums[i][j] = count;
count++;
}
//下边:列j改变(j=n-offset),行i不变(i= n-offset).遵循左闭右开原则,列不对左边最后一个元素操作
for (; j > startY; j--) {
nums[i][j] = count;
count++;
}
//左边:列j不变(j=startY),行i改变((i= n-offset)). 遵循左闭右开原则,行不对左边最后一个元素操作
for (; i > startX; i--) {
nums[i][j] = count;
count++;
}
startX++;
startY++;
offset++;
loop++;
}
//3、n 为奇数时,单独处理矩阵中心的值
if (n % 2 == 1) {
nums[startX][startY] = count;
}
//4、返回数据
return nums;
Tips:
边界条件一定要一致,这里使用左闭右开,
在进行数据填充时,区间右边的数据由下家处理,按顺时针方向最终完成数据填充。
区间和(模拟笔试)
题目链接:点击跳转-题目链接
思路:用到数组常用的解题技巧–前缀和。前缀和的思想是重复利用计算过的子数组之和,从而降低区间查询需要累加计算的次数。
import java.util.Scanner;
public class Main{
public static void main(String[] arges){
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 java.util.Scanner;
//定义主类和主方法
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int m = scanner.nextInt();
int sum =0;
int[][] vec = new int[n][m];
for(int i =0;i<n;i++){
for(int j = 0;j<m;j++){
vec[i][j] = scanner.nextInt();
sum += vec[i][j];
}
}
//统计横向
int[] horizontal = new int[n];
for(int i = 0;i<n;i++){
for(int j = 0;j<m;j++){
horizontal[i] += vec[i][j];
}
}
//统计纵向
int[] vertical = new int[n];
for(int j = 0;j<n;j++){
for(int i = 0;i<m;i++){
vertical [j] += vec[i][j];
}
}
int result = Integer.MAX_VALUE;
int horizontalCut = 0;
//横向切割
for(int i = 0;i<n;i++){
horizontalCut += horizontal[i];
result = Math.min(result, Math.abs((sum-horizontalCut)-horizontalCut));
//上行代码中的 (sum-horizontalCut)-horizontalCut 等同于 sum - 2 * horizontalCut
}
//纵向切割
int verticalCut = 0;
for (int j = 0; j < m; j++) {
verticalCut += vertical[j];
result = Math.min(result, Math.abs(sum - 2 * verticalCut));
}
//输出横向和竖向切割两种方式中切割后,矩阵两部分的最小值差值
System.out.println(result);
scanner.close();
}}