文章目录
代码随想录开源LeetCode题单:代码随想录
题目
1.LeetCode209
1.1 滑动窗口
1.1.1 思路
滑动窗口定义了起始位置和终止位置两个索引来将元素框在其中,在改变终止位置的同时让起始位置做出对应的改变,实现窗口的滑动,从而得到符合要求的结果。
题目要求寻找元素和大于等于target
的最小子数组,可以使用滑动窗口。
定义一个f循环体,终止位置从0
开始后移直至数组中最后一个元素,在循环体中,
- 终止位置
right
每后移一位就向当前和sum
中加入nums[right]
。 - 一旦当前和
sum
大于等于target
,就记录当前的滑动窗口长度subL
,即right-left+1
。更新返回结果result
为subL
和result
中的较小值。 - 当前和
sum
减去起始位置元素,起始位置left
后移一位,即实现滑动窗口的滑动。
循环结束后,检查返回结果result
是否改变,若未改变则说明没有找到最小子数组。
时间复杂度:O(n)
1.1.2 代码
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int left = 0, // 滑动窗口起始位置
right = 0, // 滑动窗口终止位置
sum = 0, // 滑动窗口内元素和
subL = 0, // 满足`sum >= target`的最小子数组长度
result = Integer.MAX_VALUE; // 返回值,同时最大整数用于标记该值是否发生改变
for(left = 0, right = 0; right < nums.length; right++){
// 求滑动窗口内元素的和
sum += nums[right];
while(sum >= target){
subL = right -left + 1; // 当前满足要求的滑动窗口长度
result = subL < result ? subL : result; // 记录最小长度
sum -= nums[left++];
}
}
// 若result值未更新,则不存在符合条件的子数组,返回0
return result == Integer.MAX_VALUE ? 0 : result;
}
}
1.2 前缀和+二分查找
解法来源:LeetCode精选题解 4
1.2.1 思路
申请临时数组 sums
, sums[i]
表示nums
前 i
个元素的和,
题中说nums
元素为正整数,则相加的和越来越大,即是sums
数组中的元素是递增的。
只需要找到 sums[k]-sums[j]>=s
,则 k-j
就是满足的连续子数组,但不一定是最小的,所以要继续找,直到找到最小的为止。
为避免双重for循环暴力求解,可以把求sums[k]-sums[j]>=s
变为求 sums[j]+s<=sums[k]
,因为sums
中元素递增的,故只需要求sum[j]+s
的值,然后使用二分法查找即可找到这个 k
。
时间复杂度:O(nlogn)
1.2.2 代码
public int minSubArrayLen(int s, int[] nums) {
int length = nums.length;
int min = Integer.MAX_VALUE;
int[] sums = new int[length + 1];
for (int i = 1; i <= length; i++) {
sums[i] = sums[i - 1] + nums[i - 1];
}
for (int i = 0; i <= length; i++) {
int target = s + sums[i];
int index = Arrays.binarySearch(sums, target);
if (index < 0)
index = ~index;
if (index <= length) {
min = Math.min(min, index - i);
}
}
return min == Integer.MAX_VALUE ? 0 : min;
}
2.LeetCode59
2.1 思路
本题要求从外圈到内圈顺时针填充矩阵,模拟图如下。
每一圈都应按照
- 左–>右、上–>下、右–>左、下–>上 的顺序来填充。
遵循循环不变量原则,每一段都取左闭右开区间。
2.2 代码
class Solution {
public int[][] generateMatrix(int n) {
int[][] result = new int[n][n];
int cnt = 0, // 圈数索引
num = 1; // 待填充数值
//无论奇数圈还是偶数圈,索引都不超过(n + 1) / 2
while(cnt < (n + 1) / 2){
int i = 0 + cnt,
j = 0 + cnt;
while(j < n - cnt){ //左-->右
result[i][j++] = num++;
}
j--; num--;
while(i < n - cnt){ //上-->下
result[i++][j] = num++;
}
i--; num--;
while(j >= 0 + cnt){ //右-->左
result[i][j--] = num++;
}
j++; num--;
while(i > 0 + cnt){ //下-->上
result[i--][j] = num++;
}
i++; //num--;
cnt++;
}
return result;
}
}
3.KamaCoder58
3.1 思路
3.2 代码
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();
}
}
4.KamaCoder44
4.1 思路
前缀和
代码随想录 文章讲解
4.2 代码
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[m];
for (int j = 0; j < m; j++) {
for (int i = 0; i < n; 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 - 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();
}
}