#算法练习#数组#LeetCode
今天练习的题目是leetcode 209(209. 长度最小的子数组 - 力扣(LeetCode))和59(59. 螺旋矩阵 II - 力扣(LeetCode)),依然数数组的题目,螺旋矩阵是对二位数组的处理。
209.长度最小的子数组
这道题目有两种解法,我看到题目第一感觉暴力解法,两个循环,挨个子数组求和然后跟target做比较,但是因为粗心,这里耗费了一点时间,求和时将sum = sum + nums[j] 直接写成了下标:sum = sum + j ,时间就是金钱,难受啊。这个是第一版(粗心报错版):
public int minSubArrayLen(int target, int[] nums) {
if(null == nums) {
return 0;
}
int length = nums.length;
int min = length + 1;
int sum = 0;
//violent solution
for(int i = 0; i < length; i++) {
sum = nums[i];
if(sum >= target) {
min = 1;
}
for(int j = i+1; j < length; j++) {
sum = sum+j; // 这里写错了,查了半天,看代码逻辑应该不会错呀
if(sum >= target) {
min = Math.min(min, (j-i+1));
break;
}
}
}
return min>length ? 0:min;
}
暴力解法最终完成代码:
public int minSubArrayLen(int target, int[] nums) {
if(null == nums) {
return 0;
}
int length = nums.length;
int min = length + 1;
int sum = 0;
//violent solution
for(int i = 0; i < length; i++) {
sum = nums[i];
if(sum >= target) {
min = 1;
break;
}
for(int j = i+1; j < length; j++) {
sum = sum+nums[j];
if(sum >= target) {
min = Math.min(min, (j-i+1));
break;
}
}
}
return min>length ? 0:min;
}
虽然暴力解法逻辑是合理的,但是时间复杂度是O(n平方),leetcode提交是超时的,过不了。也跟其他大神做了下比较,代码还是有点冗余,但是几乎没有做改动,主要是记录当时自己的想法。
另一种方法就是卡尔推荐的滑动窗口,也是一种双指针的解法,只是这个双指针的移动比较特殊和巧妙。通过双指针pre和cur,pre记录滑动窗口结束的位置,cur记录开始的位置,也就是不断搜索的位置,找到子数组的和大于target时,通过移动cur来缩小窗口,找最小的目标子数组。具体代码:
public int minSubArrayLen(int target, int[] nums) {
if(null == nums) {
return 0;
}
int length = nums.length;
//two pointers or slide window algorithm
int cur = 0;
int sum = 0;
int res = length + 1;
for(int pre = 0; pre < length; pre++) {
sum += nums[pre];
while(sum >= target) {
res = Math.min(res, (pre-cur +1));
sum -= nums[cur];
cur++;
}
}
return res>length ? 0:res;
}
59.螺旋矩阵 II
这道题开始看到题目是比较懵的,因为平时很少用到二维数组,也没有将矩阵和二位数组联系在一起,早上上班的地铁上一直在琢磨是怎么处理,突然一下就想通了,这个不就是二维数组吗,现在的目标就是如何找到对应的数组下标的值,也就是解决螺旋的问题。
首先是几次螺旋,通过观察,螺旋次数 = n/2.
每一次螺旋就是针对四条边的处理,以i和j作为数组下标,即:
i不变,j从起始位置到目标位置
j不变,i从起始位置到目标位置
i不变,j从当前位置到起始位置前一个位置(因为这里有个偏移量,也就是区间是左闭右开区间)
j不变,i从当前位置到其实为止前一个位置。
具体的代码:
public int[][] generateMatrix(int n) {
int[][] res = new int[n][n];
int num = 1;
int startX = 0, startY = 0; //螺旋的起始位置
int offset = 1; //偏移量,每一次螺旋的大是在减小的
int loopCount = n/2; //螺旋次数
int i,j; //坐标
while(loopCount > 0) {
for(j = startY; j < n-offset; j++) {
res[startX][j]= num++;
}
for(i = startX; i < n-offset; i++) {
res[i][j]= num++;
}
for(;j > startY; j--) {
res[i][j]= num++;
}
for(;i > startX; i--) {
res[i][j]= num++;
}
loopCount--;
offset++;
startX++;
startY++;
}
if(n%2 == 1) {
int center = n/2; //奇数位最后一个补齐的坐标(center, center),偶数位无需 补齐
res[center][center]= num;
}
return res;
}
个人感觉想通了思路不是很难,主要是很多细节需要注意,整个debug过程还是会耗费一定的时间。
后面的练习继续加油吧!