目录
977 有序数组的平方
看到题目的第一想法:这道题之前有遇到过,第一思路是判断数组是否是全为正数或者全为负数,对上面这两种情况单独处理;如果数组既包含正数也包含负数,就找到第一个出现的正数,而后拿两个指针分别向左右移动,但是这块的处理上一直无法ac,后面在仔细研究一下。
看完代码随想录之后的想法:卡哥的方法清晰明了~
代码实现:
我的思路:
- 对于有break的for循环,当break的时候,后面那次i++是不执行的;所以处理后面的循环时i+1;
- 当一侧到边界的时候,另一侧肯定未到边界,比如左侧已越界,需要right < length写到判断条件上,防止越界异常;
class Solution {
public int[] sortedSquares(int[] nums) {
//有思路,但是查找了第一个正数,而后代码写的也无法通过。。看到卡哥的写法,茅塞顿开,原来这么简单。。
//o(n)的时间复杂度,要使用双指针才行
int length = nums.length;
if(length == 0) {
return new int[0];
}
int[] result = new int[length];
if (length > 0 && nums[length - 1] <= 0) {
for (int i = 0; i < length; i++){
result[i] = nums[length - 1 - i] * nums[length - 1 - i];
}
return result;
}
if (length > 0 && nums[0] >= 0) {
for (int i = 0; i < length; i++){
result[i] = nums[i] * nums[i];
}
return result;
}
//寻找第一个正数
int index = 0;
for(int i = 0; i < length; i++) {
if(nums[i] >= 0) {
index = i;
break;
}
}
//此时index必然>=1
int left = index - 1;
int right = index;
int i = 0;
for(; i < length; i++){
if (nums[left] * nums[left] <= nums[right] * nums[right]) {
result[i] = nums[left] * nums[left];
left--;
if(left < 0){
//到边界即跳出
break;
}
}else {
result[i] = nums[right] * nums[right];
right++;
if(right >= length){
//到边界即跳出
break;
}
}
}
//当一侧到边界的时候,另一侧肯定未到边界,比如左侧已越界,需要right < length写到判断条件上,防止越界异常
//此情况是左侧到边界,而右侧未到
if(left == -1 && right < length) {
//对于有break的for循环,当break的时候,后面那次i++是不执行的;所以处理后面的循环时i+1;
for (i = i + 1; i < length; i++) {
result[i] = nums[right] * nums[right];
right++;
}
}
//此情况为右侧到边界,而左侧未到
if(right == length && left >= 0) {
for (i = i + 1; i < length; i++) {
result[i] = nums[left] * nums[left];
left--;
}
}
return result;
}
}
代码随想录提供的方法:
class Solution {
public int[] sortedSquares(int[] nums) {
int length = nums.length;
int l = 0;
int r = length - 1;
int[] result = new int[length];
int index = length - 1;
while (l <= r) {
if (nums[l] * nums[l] <= nums[r] * nums[r]) {
result[index--] = nums[r] * nums[r];
r--;
}else {
result[index--] = nums[l] * nums[l];
l++;
}
}
return result;
}
}
实现过程中遇到哪些困难:
- 寻找到第一个正数后,如果对元素的平方进行排序 ?
- 相关部分代码见上方我的思路
209 长度最小的子数组
看到题目的第一想法:这题之前刷过,知道要用华东窗口来处理,但是具体的实现上总是有些问题,题目很难ac。
- 以下面这块为例,只对sum >= target 进行处理即可,而我最开始外面使用的是while循环,条件为fast < length,但是这么写总也无法ac,现在也没有想通,后续再看看,已处理~
- 问题出在了下面两个语句的顺序上,开始是将if语句放在前面,while语句放在后面,这样就会有问题,比如fast未进行自增时,就可能出现sum>=target的情况,这样就有数据的丢失,将while语句放在if语句之前即可~
//for (;fast < length;fast++) {
while(fast < length) {
sum += nums[fast];
if(sum < target) {
fast++;
}
while (sum >= target && slow <= fast) {
result = Math.min(result, fast - slow + 1);
sum -= nums[slow++];
}
}
看完代码随想录之后的想法:单独对特殊情况处理即可,有的不需要处理。想明白之后再开始写代码!
代码实现:
- 代码随想录提供的解法中,result = Integer.MAX_VALUE;而在返回时,若是result未被赋新值就说明方法中没有符合条件的子数组,按题意返回0,否则返回被赋值的result
result == Integer.MAX_VALUE ? 0 : result
class Solution {
public int minSubArrayLen(int target, int[] nums) {
//滑动窗口
int length = nums.length;
int fast = 0, slow = 0;
int result = length;
int sum = 0;
for (int i = 0; i < length; i++) {
sum += nums[i];
}
if(sum < target) {
return 0;
}
sum = 0;
for (;fast < length;fast++) {
//while(fast < length) {
sum += nums[fast];
while(sum >= target) {
result = Math.min(result, fast - slow + 1);
sum -= nums[slow++];
}
/*if(sum < target) {
fast++;
}
while (sum >= target && slow <= fast) {
result = Math.min(result, fast - slow + 1);
sum -= nums[slow++];
}*/
}
return result;
}
}
实现过程中遇到哪些困难:
- while循环与for循环使用上还有不少的问题:
- while循环的使用依旧不是很熟练,结束条件的判定也不准确。
59 螺旋矩阵 II
看到题目的第一想法:这也是一道刷过的题,有大致的思路,但是写的时候却是无从下手。
看完代码随想录之后的想法:此题也涉及到了循环不变量,以每条边而言,都是前闭后开进行处理的。
代码实现:
class Solution {
public int[][] generateMatrix(int n) {
//之前做个这个题,有点简单的思路,但是还是有无从下手的感觉
int circle = 0;
int start = 0;
int i,j;//i为行数,j为列数
int count = 1;
//创建数组,用以存放结果
int[][] result = new int[n][n];
while (circle++ < n / 2) {
//循环不变量,前闭后开区间
//上层从左到右
for(j = start; j < n - circle; j++) {
result[start][j] = count++;
}
//右侧从上到下
for(i = start; i < n - circle; i++) {
result[i][j] = count++;
}
//下层从右到左
for (; j >= circle; j--) {
result[i][j] = count++;
}
//左侧从下到上
for (; i >= circle; i--) {
result[i][j] = count++;
}
start++;
}
if (n % 2 == 1){
result[start][start] = count;
}
return result;
}
}
实现过程中遇到哪些困难:
- 循环圈数的确定,为什么要用circle++?
- 以n=3为例,只需要一层循环即可,即为n/2,circle++则是用来方便处理下面代码中的边界问题,
- start的作用?
- 最开始为 i,j 赋值,相当于圈数-1,方便单独对中心(n为奇数时)的元素进行赋值。
今日收获,记录一下自己的学习时长
- 算法处理约3h,博客编写约2h
- 熟悉了双指针法、滑动窗口与模拟行为与双指针法,编写博客也是对自己思路的梳理~
- 贵在坚持,加油!
数组总结:
- 数组元素不能被删除,只能被覆盖;
- Java中二维数组的地址空间是不连续的,以int[3][4]为例,其由四个连续的地址控件组成,分别为1个能执行其他3个地址的空间,和其他3个长度为4的连续空间,so 1+3~
- 数组相关的算法有:二分法(循环不变量),双指针法(快慢指针降低一级时间复杂度),滑动窗口(两指针动态变化),模拟行为(行为的模拟+循环不变量)等。