目录
977.有序数组的平方
题目链接:力扣
思路
拿到题目首先想到的方法就是遍历改值,然后进行排序(这个题目真的是,递增就递增嘛,非得弄个非递减,我一开始以为数据是乱的,一开始就进行了排序,其实就算数据是乱的,一开始就进行排序也是错误的做法,因为有负数,平方后会变大,所以需要全部平方后在进行排序)这也就是一般的暴力解法
双指针思路:因为这个数组是递增的,如果数组里面全是正数,平方后也是递增的数组,如果数组里面全是负数,平方之后是递减的数组;对于有正数和有负数的数组,其实两边的数平方之后是最大的,那我们可以创建一个新的数组,开始从数组的两头开始平方,然后平方后比较大的数从新建的数组后面开始放数
需要注意一下几个细节:
- 前后两个数平方后,进行比较,大的进数组,指针移动,小的继续待命,需要下一轮比较
- 两个指针需要有相等的条件,如果不相等,会出现有元素没有进行比较的情况
有序数组的平方
暴力解法
第一步:对数组中的值进行平方
第二步:对数组进行排序
class Solution {
public int[] sortedSquares(int[] nums) {
// 先对数组进行改值
for (int i = 0 ; i < nums.length ; i++) {
nums[i] = nums[i] * nums[i];
}
// 再对数组进行排序
Arrays.sort(nums);
return nums;
}
}
双指针
第一步:创建新数组
第二步:创建新数组的指针(放在最后一位,用于放值)
第三步:创建老数组的指针(前后各一个)
第四步:平方后比较,大的搬家,小的待命
第五步:返回
注意点:
1、循环的条件要有等于情况,要不然比较完还会剩一个
2、判断的时候记得考虑等于的情况
class Solution {
public int[] sortedSquares(int[] nums) {
// 创建一个新数组
int[] newNums = new int[nums.length];
// 创建前后两个指针
int left = 0;
int right = nums.length - 1;
// 创建新数组的指针,指向最后的下标
int key = newNums.length - 1;
while (left <= right) {
if (nums[left] * nums[left] < nums[right] * nums[right]) {
// 大的被选中
newNums[key] = nums[right] * nums[right];
// 被选中的移坐标
right--;
// 新数组移下标
key--;
} else if (nums[left] * nums[left] >= nums[right] * nums[right]) {
// 大的被选中
newNums[key] = nums[left] * nums[left];
// 被选中的移坐标
left++;
// 新数组移下标
key--;
}
}
return newNums;
}
}
209.长度最小的子数组
题目链接:力扣
思路
暴力解法:首先我们会想到的就是以两层循环进行遍历,取到合适的数组
滑动窗口:想象一下推拉窗户,只不过这个滑动窗口的移动靠指针,大小靠里面的数值和,检索开始,右边的指针进行收割,把后面的数收割到窗口中,满足条件就进行判断,判断完成后就利用左边的指针推动窗口(注意判断是用while还是用if)
长度最小的子数组
暴力解法
第一步:外层循环开始,从第一个值进行判断
第二步:内层循环从外层循环下标开始的位置往后进行收割
第三步:满足条件的获得长度,跳出循环
第四步:外层循环再进一步,从第二个开始
第五步:以此循环,最终求到最小值
class Solution {
public int minSubArrayLen(int target, int[] nums) {
// 设置取数的值
int result = Integer.MAX_VALUE;
// 设置子数组的值
int sum;
for (int i = 0; i < nums.length ; i++) {
sum = 0;
for (int j = i ; j < nums.length ; j++) {
sum += nums[j];
if (sum >= target) {
int len = j - i + 1;
result = len < result ? len : result;
break;
}
}
}
return result == Integer.MAX_VALUE ? 0 : result;
}
}
滑动窗口
第一步:准备两个指针(代表的是窗口左右的两个指针,左指针控制窗口的整体移动,右指针在前面奋勇收割)
第二步:判断子数组的值的和,如果满足条件就取长度,与已有的长的进行比较
第三步:左指针控制窗口向前移动
第四步:返回之后的结果
注意点:判断和的时候是使用if还是while?
if只能减去前面一个多的元素,不能判断窗口前是不是右多个元素不满足条件,比如现在有个目标值是7,数组窗口内的数字有 1 ,1,1,1,50,那么当窗口时54的时候满足条件,但是if判断只能减去第一个1,后面的3个都减不掉,最小的满足长度的数组没有获取到
Tip:感觉双指针两层循环的一种更高效的替代
class Solution {
public int minSubArrayLen(int target, int[] nums) {
// 设置一个比较值,与获取到的子数组长度进行比较
int result = Integer.MAX_VALUE;
// 设置两个指针来圈子数组
int left = 0;
int sum = 0;
for (int right = 0 ; right < nums.length ; right++) {
sum += nums[right];
while (sum >= target) {
// 记录满足条件的子数组的长度
int len = right - left + 1;
// 将获取到的长度进行比较存储
result = result > len ? len : result;
// 移动窗口,将左指针向前进一位,同时left指针指向的数字也要从这个窗口中减去
sum -= nums[left++];
}
}
return result == Integer.MAX_VALUE ? 0 : result;
}
}
59.螺旋矩阵II
题目链接:力扣
思路:
这个题目不涉及什么算法,要求的是对代码的掌握程度,最忌的就是转多了,或者转少了,这样就乱了,所以一定要遵循循环不变量的原则进行遍历,确保每一个都能填上
1、怎么转,转几圈,转圈的条件怎么判断
2、转的时候,边界条件怎么设置(循环不变量)坚持一个原则处理每一条边,因为是个循环,所以使用左闭右开的原则来处理每一条边
3、n为奇数的情况怎么处理
螺旋矩阵II
模拟循环
while 循环是转了几圈 转了n/2圈 循环中的判断条件 从第0圈开始
这里面的offset和loop可以合成一个变量loop
startX和startY可以合成一个变量start
class Solution {
public int[][] generateMatrix(int n) {
// 创建二维数组
int[][] nums = new int[n][n];
// 二维数组的起始位置
// int[i][j]
// int[startX][startY]
int startX = 0;
int startY = 0;
// 每次循环控制边界(左闭右开)
int offset = 1;
// 放进数组的数
int count = 1;
// 因为有四个循环,将i和j设置为全局变量
int i,j;
// 要转的圈数
int loop = 0;
while (loop++ < n/2) {
// 从左到右
for (j = startY ; j < n - offset ; j++) {
nums[startX][j] = count++;
}
// 从上到下
for (i = startX ; i < n - offset ; i++) {
nums[i][j] = count++;
}
// 从右到左
for ( ; j > startY ; j--) {
nums[i][j] = count++;
}
// 从下到上
for ( ; i > startX ; i--) {
nums[i][j] = count++;
}
// 起始位置移动
startX++;
startY++;
// 控制边界量增加
offset++;
}
if (n % 2 == 1) {
nums[startX][startY] = count;
}
return nums;
}
}