209. 长度最小的子数组
第一次提交:没有考虑到right==nums.length的情况。
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int left = 0, right = 1; // 左闭右开的窗口
int res = Integer.MAX_VALUE;
int sum = 0;
// 如果数组长度为0
if (0 == nums.length){
return 0;
}else{
sum = nums[0]; // 赋初始值
}
while(right<=nums.length){
if(sum>=target){
res = res > right-left ? right-left : res;
sum -= nums[left];
left++;
}else{
sum += nums[right]; // Error:
right++;
}
}
return res == Integer.MAX_VALUE ? 0 : res;
}
}
第二次提交:只是在第一次提交的基础上修改了一下,运行成功。但还是很别扭,在纠结什么时候赋值、什么时候循环。需要进一步再研究研究,整理出合适思路。
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int left = 0, right = 1; // 左闭右开的窗口
int res = Integer.MAX_VALUE;
int sum = 0;
// 如果数组长度为0
if (0 == nums.length){
return 0;
}else{
sum = nums[0]; // 赋初始值
}
while(right<=nums.length){
if(sum>=target){
res = res > right-left ? right-left : res;
sum -= nums[left];
left++;
}else if (right==nums.length){
break;
}else{
sum += nums[right];
right++;
}
}
return res == Integer.MAX_VALUE ? 0 : res;
}
}
代码随想录的解法如下:
class Solution {
// 滑动窗口
public int minSubArrayLen(int s, int[] nums) {
int left = 0;
int sum = 0;
int result = Integer.MAX_VALUE;
for (int right = 0; right < nums.length; right++) {
sum += nums[right];
while (sum >= s) {
result = Math.min(result, right - left + 1);
sum -= nums[left++];
}
}
return result == Integer.MAX_VALUE ? 0 : result;
}
}
本题滑动窗口总结
滑动窗口的区间:左闭右闭
- 保证数组不会越界
- 可以赋初始值
滑动窗口的循环:
- for循环:右指针遍历
- while循环:找到合适的左指针
总结:固定终止位置,寻找此时的起始位置。
什么时候用for循环,什么时候用while循环?目前还是有点不懂。
Math在lang包下,可以使用。
59. 螺旋矩阵Ⅱ
一开始想着每次赋值就是一次循环,那么循环要进行2*n-1次。但是这样前后循环没有关联,写不下去了……
class Solution {
public int[][] generateMatrix(int n) {
int[][] res = new int[n][n];
int offset = 0;
int count = 2*n - 1;
for(int i=n; i>0; i--){
for(int cur = )
}
}
}
然后又看了一遍代码随想录:只能是循环按圈数来,每个循环进行四组赋值。(可以联想到,一年分四季,同比环比的意义完全不一样)
class Solution {
public int[][] generateMatrix(int n) {
int[][] res = new int[n][n];
int offset = 0; // offset的含义:赋值起始的offset,赋值终止的offset
int loop = 0;
int i,k;
int num = 1;
while(loop<n/2){
for(i = offset; i<n-offset-1; i++){ // 左闭右开 // n-offset-1的含义
res[offset][i] = num++;
}
for(i = offset; i<n-offset-1; i++){
res[i][n-offset-1] = num++;
}
for(i = n-offset-1; i>offset; i--){
res[n-offset-1][i] = num++;
}
for(i = n-offset-1; i>offset; i--){
res[i][offset] = num++;
}
// 不要忘了
loop++;
offset++;
}
// 考虑到奇数
if(1==n%2){
res[n/2][n/2] = num; // 数组下标从0开始,不要忘了
}
return res;
}
}
总结
再看代码随想录,还是有很多想法:
- 在循环时,每次
i
的范围都要在offset
到n-offset-1
之间。可以将其固定。 offset
与loop
虽然值一样,但分成两个变量,有不同的含义。offset
与loop
,是否初始值设为-1更好一点?(
区间和
关键:前缀和
这道题很容易时间超限……
import java.util.Scanner;
class Main{
public static void main(String[] args){
Scanner s = new Scanner(System.in);
int n = s.nextInt();
int[] sum = new int[n];
sum[0] = s.nextInt();
for(int i=1; i<n; i++){
sum[i] = s.nextInt() + sum[i - 1];
}
int start, end;
while(s.hasNext()){
start = s.nextInt();
end = s.nextInt();
System.out.println(sum[end] - (start==0 ? 0: sum[start-1]));
}
s.close();
}
}
总结
- 不是lang包就要手动导入:
import java.util.Scanner;
- scanner用完记得关闭……
开发商购买土地
以前做过的代码,先保存一下:
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[][] blocks = new int[n][m];
int[] sumLineN = new int[n];
int[] sumColumnM = new int[m];
int result = Integer.MAX_VALUE;
// 读取数据,并且写出每行的前缀和
for(int i=0; i<n; i++){
for(int j=0; j<m; j++){
blocks[i][j] = sc.nextInt();
// 每行的和
sumLineN[i] += blocks[i][j];
// 每列的和
sumColumnM[j] += blocks[i][j];
}
// 将每行的和,变为前缀和
if(i<n-1) sumLineN[i+1] = sumLineN[i];
}
// 土地价值总和
int sum = sumLineN[n-1];
float mid = (float)sum / 2;
// 将每列的和,变为前缀和,并遍历
for(int j=0; j<m; j++){
if(j!=0) sumColumnM[j] += sumColumnM[j-1];
result = Math.min(result, Math.abs(sum - sumColumnM[j] * 2));
}
if(result==0) {
System.out.println(result);
return;
}
// 遍历行的前缀和
for(int i=0; i<n; i++){
result = Math.min(result, Math.abs(sum - sumLineN[i] * 2));
}
System.out.println(result);
return;
}
}
以下是重写的:
import java.util.Scanner;
class Main{
public static void main(String[] args){
Scanner s = new Scanner(System.in);
int n = s.nextInt();
int m = s.nextInt();
int[][] matrix = new int[n][m];
int[] line = new int[n]; // 每行都有前缀和
int[] column = new int[m]; // 每列都有前缀和
for(int i=0; i<n; i++){
for(int k=0; k<m; k++){
matrix[i][k] = s.nextInt();
line[i] += matrix[i][k]; // 顺便求出每行的和
column[k] += matrix[i][k];
}
line[i] = line[i] + (i==0?0:line[i-1]); // 已经是前缀和了
}
for(int k=0; k<m; k++){
column[k] = column[k] + (k==0?0:column[k-1]);
}
int res = Integer.MAX_VALUE;
for(int i=0; i<n; i++){
res = Math.min(res, Math.abs(line[n-1] - 2*line[i]));
}
for(int k=0; k<m; k++){
res = Math.min(res, Math.abs(column[m-1] - 2*column[k]));
}
System.out.println(res);
}
}