209.长度最小的子数组
Leetcode链接: link
class Solution {
public static int minSubArrayLen(int target, int[] nums) {
int front = 0;
int end = 0;
int sum = 0;
int result = 0;
while(end < nums.length){
sum += nums[end];
while(sum >= target){
if(result == 0){
result = end-front+1;
}else{
result = Math.min(result, end-front+1);
}
sum -= nums[front];
front ++;
}
end++;
}
return result;
}
}
这一题我写了很久,一开始就知道需要使用滑动窗口来解决,但是我一开始并没有使用两个loop。导致我写的异常的艰难。而且还在一开始没看清题目,以为只能写“子数组总和等于 target 的长度最小的子数组”。后面写出来发现怎么也过不了,就选择了看答案。看到使用两个loop之后茅塞顿开。下面是我第一次的代码,我觉得写起来也挺有意义的,虽然花费了很长的时间才理清楚指针的移动逻辑。
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int n = nums.length;
if (n == 0) {
return 0;
}
int front = 0;
int end = 0;
int sum = 0;
int result = 0;
while(front < n){
if(sum < target){
if(end >= n){
break;
}
sum += nums[end];
end ++;
}else if(sum > target){
sum -= nums[front];
front++;
}else{
if(result == 0){
result = end-front;
}else{
result = Math.min(result, end-front);
}
sum -= nums[front];
front++;
}
}
return result;
}
}
59.螺旋矩阵II
Leetcode链接: link
class Solution {
public int[][] generateMatrix(int n) {
int x = 0;
int y = 0;
int [][] matrix = new int[n][n];
int count = 1;
for(int i = 0; i < n/2; i++){
for(; y < n-i-1; y++){
matrix[x][y] = count;
count++;
}
for(; x < n-i-1; x++){
matrix[x][y] = count;
count++;
}
for(; y > i; y--){
matrix[x][y] = count;
count++;
}
for(; x > i; x--){
matrix[x][y] = count;
count++;
}
x++;
y++;
}
if(n%2 == 1){
matrix[x][y] = count;
}
return matrix;
}
}
这题一拿到手上就知道该怎么做了,定义一个matrix,然后在旋转修改里面的值。一开始写的很正常,写的是最外面的循环。但是后面就出问题了。我一开始的for循环是这样的:
for(; y < n-1; y++)
for(; x < n-1; x++)
for(; y > 0; y--)
for(; x > 0; x--)
这只是对最外面进行了循环并没有对里面进行循环。我也是debug了很久才知道该怎么做。把i加入进去。修改之后变成了这样:
for(; y < n-i; y++)
for(; x < n-i; x++)
for(; y > i; y--)
for(; x > i; x--)
现在看来真是脑子瓦特了。debug修改这个loop就花了我将近半小时。不得不说写代码是真的花费时间的事情。
59.前缀和算法
链接: link
这种方法应该是算区间和最快的方法了。这题也很巧妙的在读取用户输入的时候就可以生成我们的“前缀和array”。如果不是这种读取模式的话,我觉得应该是还是直接用for循环把直接取出里面数组加在一起会更快。
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
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();
}
}
59.开发商购买土地
#include <iostream>
#include <vector>
#include <climits>
using namespace std;
int main () {
int n, m;
cin >> n >> m;
int sum = 0;
vector<vector<int>> vec(n, vector<int>(m, 0)) ;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
cin >> vec[i][j];
sum += vec[i][j];
}
}
// 统计横向
vector<int> horizontal(n, 0);
for (int i = 0; i < n; i++) {
for (int j = 0 ; j < m; j++) {
horizontal[i] += vec[i][j];
}
}
// 统计纵向
vector<int> vertical(m , 0);
for (int j = 0; j < m; j++) {
for (int i = 0 ; i < n; i++) {
vertical[j] += vec[i][j];
}
}
int result = INT_MAX;
int horizontalCut = 0;
for (int i = 0 ; i < n; i++) {
horizontalCut += horizontal[i];
result = min(result, abs(sum - horizontalCut - horizontalCut));
}
int verticalCut = 0;
for (int j = 0; j < m; j++) {
verticalCut += vertical[j];
result = min(result, abs(sum - verticalCut - verticalCut));
}
cout << result << endl;
}
这题是把上面那一题的前缀和算法演变成了2D数组的前缀和求法。先在读取用户输入的时候顺便把2D数组里所有的数字加起来找到sum。然后再循环分别求出每一行的sum和每一列的sum,分别放入两个array。最后对这两个array进行遍历。
难点:
horizontalCut += horizontal[i];
result = min(result, abs(sum - horizontalCut - horizontalCut));
这两个代码,我思考了很久才看明白。本质上abs(sum - horizontalCut - horizontalCut)就是等于切割了2D array并且算出了左右两边的差值。
下面就是我自己为了方面记忆写的一个例子。
我们先是得出sum = 51,我们从6开始,sum - horizontalCut - horizontalCut就等于后面全部element的加起来减去6。下一个15,我们的cut就要变成15+6 = 21.
今日收获
复习了滑动窗口。学习了前缀和(也可能之前学过忘了)好像有点印象。虽然滑动窗口花费了自己大量的时间,但是以后应该写起来不会那么困难。还有前缀和的多种用法。感觉真的很难,就算是知道了可能也不太会应用。
记录一下自己的学习时长:
leetcode:3h
博客:0.5h