977. 有序数组的平方
思路放在代码里啦~
1.暴力求解(Java自带排序函数Arrays.sort()的使用)
class Solution {
public int[] sortedSquares(int[] nums) {
1.暴力解法(利用Java自带排序函数)
int[] s = new int[nums.length];
for(int i = 0; i < nums.length; i ++ ){
s[i] = nums[i]*nums[i];
}
//直接用自带的排序函数 void Arrays.sort(int s[]);
Arrays.sort(s);
return s;
}
}
2.双指针法
class Solution {
public int[] sortedSquares(int[] nums) {
// 2.双指针法
int[] s = new int[nums.length];
int k = nums.length - 1; // k从数组尾开始往前移动
int i,j; // i,j指针
i = 0;j = nums.length - 1;
while(i <=j ){// 一旦i超过j,则退出程序
if(nums[j]*nums[j] > nums[i]*nums[i]){// j指针所指数值更大,把大的赋值给s[k]
s[k] = nums[j]*nums[j];
k--;
j--; // 记得移动k和j
}else{
s[k] = nums[i]*nums[i];
k--;
i++; // i向前移动
}
}
return s;
}
}
总结
这道题特点就是,最大值一定只出现在两头,而且越往中间越小,很符合 双指针 “双向奔赴”的感觉,然后,k是来记录新数组下标的,随着k的移动,生成新的数组。
209.长度最小的子数组
1.暴力求解(用到了三目运算符)
哈哈哈,只是练练代码能力,显然力扣不让暴力解这道题了
class Solution {
public int minSubArrayLen(int target, int[] nums) {
// 1.暴力解法
int minLength,sum;
boolean exiMinLength = false; // 判断是否存在和大于等于target的子数组
minLength = nums.length;sum = 0; // minLength应该从最坏的长度开始
for(int i = 0 ; i < nums.length ; i ++){
sum = 0; // 清空sum
for(int j= i ; j < nums.length ; j++){
sum += nums[j]; // 从第i个累加到第j个数
if(sum >= target){ // 如果和>=sum了,说明目前这个i和j之间的距离“可能”就是长度最小的子数组
exiMinLength = true; // 说明至少存在一个子数组
// 如果目前i和j之间的距离小于最小长度minLength,那么更新minLength
minLength = (minLength > (j - i + 1))?(j - i + 1):minLength;
break;
}
}
}
if(exiMinLength) return minLength;
else return 0;
}
}
2.滑动窗口法
class Solution {
public int minSubArrayLen(int target, int[] nums) {
// 2.双指针法(滑动窗口法)
int result = Integer.MAX_VALUE; // Java中int类型的最大值(存放在Integer包装类中)
int i = 0; // 起始指针i
int sum = 0;
int subLength = 0; // 子数组长度
for(int j = 0; j < nums.length; j ++){
sum += nums[j];
while(sum >= target){ // 当sum大于目标值了,就进入循环,并且开始“循环”移动起始指针i,因为有可能一次移动不够,所以要循环移动
subLength = j - i + 1; // 更新子数组长度
result = subLength < result ? subLength : result;// 更新结果值
// 先减i指针对应的数值(缩小窗口)
sum -= nums[i];
i++; // 和题解中sum -= nums[i++]一个意思
}
}
return result == Integer.MAX_VALUE ? 0 :result;//如果从来没更新过result,说明不存在大于目标值的子数组和
}
}
总结
在浙大版《数据结构》第一章“[算法1.4] 在线处理”中好像看过类似的思想,这题优化暴力解法的关键思想在于:先查找到符合“总和大于等于 target
的子数组”(sum+=nums[j++]),然后在满足条件的情况下,尽可能的压缩子数组(sum-=nums[i++]),使得最终,达到“长度最小的子数组”的要求。
59.螺旋矩阵II
一开始没什么思路,先看了一遍讲解视频,然后有思路了,但是自己写就出现了很多问题,对于“循环不变量”设置区间的问题这个我解决了,问题出在没能及时更新下一次走圈的初始值(没更新i和j)以及每条边的循环条件(onceLength)
class Solution {
public int[][] generateMatrix(int n) {
int[][] s = new int[n][n];// 动态开辟数组空间不能int [n][n]
int i = 0;
int j = 0; // 矩阵(i,j)
int onceLength = 1; // n - onceLength表示一条边的长度,所以取名为“一次长度”
int count = 1;
int startX = 0;
int startY = 0; // 第k圈的起始点(startX,startY)
// 开始循环模拟矩阵 (“左闭右开”型:取首不取尾型)
int k = 1;
while(k <= n/2){ // 循环次数是圈数,例如n = 4时,每走完一圈,行/列是不是都少两行/列,所以,一共就走n/2 = 2就够了(奇数的话,会空出中间的空缺,等到退出循环再加上即可)
for(j = startY; j < n - onceLength; j++){// 先是j(列)先走,注意起始点会随着圈数改变,所以是个变量,循环终止条件也是,是n - onceLength,是会随着循环圈数改变的
s[i][j] = count++;
}
for(i = startX; i < n - onceLength; i++){
s[i][j] = count++;
}
for(; j > startY; j--){
s[i][j] = count++;
}
for(; i > startX; i--){
s[i][j] = count++;
}
// 四次循环结束之后(一圈结束之后)别忘了更新起始位置,还有更新onceLength
i = ++startX;
j = ++startY;
onceLength++;
k++;
}
if(n%2 == 1) s[i][j] = count;
return s;
}
}
总结
这题用的循环不是一般的嵌套循环,刚开始思考这道题的时候脑海里还是用嵌套循环,所以一直想不到模拟的方法,然后看完卡哥的视频后发现就是按每一条边来设置循环的,第一次做模拟的题,思维还不够发散。这道题的关键就是注意每次变的起始位置和终止位置,这两个位置都需要及时更新并尊选“循环不变量”原则,还是很有趣的。