209.长度最小的子数组
给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的 连续 子数组,并返回其长度。如果不存在符合条件的子数组,返回 0。
示例:
- 输入:s = 7, nums = [2,3,1,2,4,3]
- 输出:2
- 解释:子数组 [4,3] 是该条件下的长度最小的子数组。
提示:
- 1 <= target <= 10^9
- 1 <= nums.length <= 10^5
- 1 <= nums[i] <= 10^5
思路:
滑动窗口:2个指针,头指针用于遍历,尾指针不动,当满足条件的结果出现后,尾指针逐步移动,再进行判断,如此往复直至结束。
代码:
public int minSubArrayLen(int target, int[] nums) {
int len = nums.length;
int sum = 0;
int result = Integer.MAX_VALUE;
int first =0;
for(int end=0; end < len; end++){
sum+=nums[end];
while(sum>=target){
//找到满足条件的子数组,记录数组长度
result = Math.min(result, end - first + 1);
//重点是这个代码,指针向右移动,总和也要相应变化,向后移动
sum -= nums[first++];
}
}
return result == Integer.MAX_VALUE ? 0 : result;
}
59.螺旋矩阵II
给定一个正整数 n,生成一个包含 1 到 n^2 所有元素,且元素按顺时针顺序螺旋排列的正方形矩阵。
示例:
输入: 3
输出: [ [ 1, 2, 3 ], [ 8, 9, 4 ], [ 7, 6, 5 ] ]
思路:
类似二分法思想,重点是确定区间边界,左闭右闭还是左闭右开,本题采用左闭右开
代码:
public int[][] generateMatrix(int n) {
int[][] result = new int[n][n];
//每圈的起始坐标,实际上startX和startY只需要用一个即可,因为二者始终相等,用2个方便理解
int startX = 0;
int startY = 0;
int count = 1;
//行
int i ;
//列
int j ;
//循环的圈数,结束循环的条件以及缩圈用,每缩一圈,循环次数少1
int loop = 1;
//采取左闭右开方式
while(loop <= n/2){
//上
for(j = startY; j< n-loop; j++){
result[startX][j] = count++;
}
//右
for(i = startX; i< n-loop; i++){
result[i][j] = count++;
}
//下
for(; j> startY; j--){
result[i][j] = count++;
}
//左
for(; i> startX; i--){
result[i][j] = count++;
}
startX++;
startY++;
loop++;
}
if(n%2!=0){
result[startX][startY] = count;
}
return result;
}
区间和
题目描述
给定一个整数数组 Array,请计算该数组在每个指定区间内元素的总和。
输入描述:
第一行输入为整数数组 Array 的长度 n,接下来 n 行,每行一个整数,表示数组的元素。随后的输入为需要计算总和的区间,直至文件结束。
输出描述:
输出每个指定区间内元素的总和。
输入示例
5
1
2
3
4
5
0 1
1 3
输出示例
3
9
数据范围:
0 < n <= 100000
思路:
在涉及计算区间问题时,采用前缀和的方式,前缀和思想是重复利用计算过的子数组之和,减少重复计算。
代码:
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int len = scanner.nextInt();
int[] nums = new int[len];
int[] preSum = new int[len];
int sum = 0;
for (int i=0;i<len ; i++){
nums[i] = scanner.nextInt();
sum += nums[i];
preSum[i] = sum;
}
while(scanner.hasNextInt()){
int first = scanner.nextInt();
int end = scanner.nextInt();
int result;
if(first == 0){
result = preSum[end];
}else{
result = preSum[end] - preSum[first-1];
}
System.out.println(result);
}
scanner.close();
}
开发商购买土地
题目描述:
在一个城市区域内,被划分成了n * m个连续的区块,每个区块都拥有不同的权值,代表着其土地价值。目前,有两家开发公司,A 公司和 B 公司,希望购买这个城市区域的土地。
现在,需要将这个城市区域的所有区块分配给 A 公司和 B 公司。
然而,由于城市规划的限制,只允许将区域按横向或纵向划分成两个子区域,而且每个子区域都必须包含一个或多个区块。 为了确保公平竞争,你需要找到一种分配方式,使得 A 公司和 B 公司各自的子区域内的土地总价值之差最小。
注意:区块不可再分。
输入描述:
第一行输入两个正整数,代表 n 和 m。
接下来的 n 行,每行输出 m 个正整数。
输出描述:
请输出一个整数,代表两个子区域内土地总价值之间的最小差距。
输入示例:
3 3
1 2 3
2 1 3
1 2 3
输出示例
0
提示信息
如果将区域按照如下方式划分:
1 2 | 3
2 1 | 3
1 2 | 3
两个子区域内土地总价值之间的最小差距可以达到 0。
数据范围:
1 <= n, m <= 100;
n 和 m 不同时为 1。
思路:
难点在于理解题目意思,转换成比较区间和的问题,采用前缀和,或更优化的解,在每行或每列末尾进行一次判断,
代码:
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int m = sc.nextInt();
//记录当前二维数组
int[][] nums = new int[n][m];
int result = Integer.MAX_VALUE;
int sum = 0;
for (int i=0; i<n; i++){
for (int j=0; j<m; j++){
nums[i][j] = sc.nextInt();
sum += nums[i][j];
}
}
//遍历行
int counti =0;
for (int i=0; i<n; i++){
for (int j=0; j<m; j++){
counti+= nums[i][j];
if(j == m-1){
//在行末进行判断,相当于以当前行为分隔线
result = Math.min(result, Math.abs(sum - 2*counti));
}
}
}
//遍历列
int countj =0;
for (int j=0; j<m; j++){
for (int i=0; i<n; i++){
countj += nums[i][j];
if(i == n-1){
//在列末进行判断,相当于以当前列为分隔线
result = Math.min(result, Math.abs(sum - 2*countj));
}
}
}
System.out.println(result);
sc.close();
}
结合昨天的文章,2天涉及到的指针,简单总结下:
1、移除元素:快慢指针:快指针用于遍历,慢指针用于保存符合要求的元素;
2、有序数组的平方:双指针:一个指向起始位置,一个指向终止位置,然后向中间移动;
3、长度最新的子数组:滑动窗口:也是2个指针,头指针用于遍历,尾指针不动,当满足条件的结果出现后,尾指针逐步移动,再进行判断,如此往复直至结束;

被折叠的 条评论
为什么被折叠?



