1.基础知识
无
2.相关知识
无
3.力扣题目
3.1 977 有序数组平方
3.1.1 自己做法
双指针法想到了一点,但是指针运用错误。
参考做法是俩指针分别指向原数组的头尾,这样相遇时循环就可以停止。
我的做法是俩指针一个指向第一个非负数,一个指向最后一个/第一个负数,(参考先找最大数,我是先找最小数)这样一直没找到循环终止的条件(想到left<0 & right >nums.length - 1就可以停止,再得到left和right具体数,把没有到的剩下的直接插入(但感觉算法题肯定不会弄得这么繁琐就没写(哭,csdn为什么没有表情包啊啊啊啊啊))),所以没做出来。知道这点后成功写出。
class Solution {
public int[] sortedSquares(int[] nums) {
int[] result = new int[nums.length];
int left = 0;
int right = nums.length - 1;
int index = nums.length - 1;
for(int i = 0;i < nums.length; i++){
nums[i] = nums[i]*nums[i];
}
while(left <= right){
if(nums[left] > nums[right]){
result[index] = nums[left];
left++;
index--;
}else{
result[index] = nums[right];
right--;
index--;
}
}
return result;
}
}
出现的问题(快反思)
在Java中,局部变量在使用之前必须被初始化。
3.1.2 参考做法
- 数组平方的最大值就在数组的两端,不是最左边就是最右边,不可能是中间。
- 此时的时间复杂度为O(n),暴力排序的解法O(n + nlog n)
class Solution {
public int[] sortedSquares(int[] nums) {
int l = 0;
int r = nums.length - 1;
int[] res = new int[nums.length];
int j = nums.length - 1;
while(l <= r){
if(nums[l] * nums[l] > nums[r] * nums[r]){
res[j--] = nums[l] * nums[l++];
}else{
res[j--] = nums[r] * nums[r--];
}
}
return res;
}
}
3.2 209 长度最小的子数组
3.2.1 自己做法
第一想法:循环取数组的第i个元素,然后顺着他往后相加,总和>=target之后,输出长度(存入一个数组里然后取最小输出/定义一个变量,存入这个变量,直到下一个长度出现比较,始终存最小的)
//结果:超出时间限制(代码随想录上的暴力解法也是超时(所以可能是对的吧))
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int sum = 0;
int count = 0;
for(int i = 0; i <= nums.length - 1; i++){
int j = i;
while(sum < target){
sum = sum + nums[i];
if(i < nums.length - 1){
i++;
}else{
if(sum >= target){
i++;
}
break;
}
}
if(sum >= target){
int count2 = i - j;
if(count == 0 | count2 < count){
count = count2;
}
}
i = j;
sum = 0;
}
return count;
}
}
//看完思路自己写的:和参考的区别就是一开始长度的赋值,参考为极大值,我为0.
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int left = 0;
int sum = 0;
int count = 0;
for(int right = 0; right <= nums.length - 1; right++){
sum = sum + nums[right];
while(sum >= target){
int count2 = right - left + 1;
if(count != 0){
count = Math.min(count,count2);
}else{
count = count2;
}
sum = sum - nums[left];
left++;
}
}
return count;
}
}
出现的问题(快反思)
- 三元运算符里不能使用赋值语句。
- count = Math.min(count,count2);求最大max或最小值min函数
3.2.2 参考做法
数组操作中一个重要的方法:滑动窗口
滑动窗口:不断的调节子序列的起始位置和终止位置,从而得出我们要想的结果。
窗口就是满足其和 ≥ s 的长度最小的 连续子数组。
窗口的起始位置如何移动:如果当前窗口的值大于等于s了,窗口就要向前移动了(也就是该缩小了)。
窗口的结束位置如何移动:窗口的结束位置就是遍历数组的指针,也就是for循环里的索引。
(第一个和>s的子数组,结束位置少一个肯定就<s了,所以要找最小的,就要试着从起始少一个看达没达到要求,这也就是上面说的起始指针的移动)
(就是小了结束往后移,大了起始往后移)
class Solution {
// 滑动窗口
public int minSubArrayLen(int s, int[] nums) {
int left = 0;
int sum = 0;
int result = Integer.MAX_VALUE;
for (int right = 0; right < nums.length; right++) {
sum += nums[right];
while (sum >= s) {
result = Math.min(result, right - left + 1);
sum -= nums[left++];
}
}
return result == Integer.MAX_VALUE ? 0 : result;
}
}
3.3 59 螺旋矩阵
3.2.1 自己做法
第一想法:自己在IDEA上运行n=3或4成功了,但是在力扣上显示超过时间限制(循环应该用太多了,还是暴力解法)
//自己的想法是按count大小判断是否停止
public class _59 {
public static void main(String[] args) {
int n = 4;
int[][] nums= new int[n][n];
int count = 1;
int one = 0;
int two = 0;
int sum = 0;
while(count <= n * n){
int key = 1;
one = sum;
two = sum;
switch(key){
case 1:
while(two < n-1-sum){
nums[one][two] = count;
two++;
count++;
if (count > n * n){
break;
}
}
if (count > n * n){
break;
}
case 2:
while(one < n-1-sum){
nums[one][two] = count;
one++;
count++;
if (count > n * n){
break;
}
}
if (count > n * n){
break;
}
case 3:
while(two > 0+sum){
nums[one][two] = count;
two--;
count++;
if (count > n * n){
break;
}
}
if (count > n * n){
break;
}
case 4:
while(one > 0+sum){
nums[one][two] = count;
one--;
count++;
if (count > n * n){
break;
}
}
if (count > n * n){
break;
}
}
sum++;
}
for(int i = 0; i < nums.length; i++){
for(int j = 0; j < nums[i].length; j++){
System.out.println(nums[i][j]);
}
}
}
}
//看了参考思路,用圈数作为停止条件
class Solution {
public int[][] generateMatrix(int n) {
int[][] nums= new int[n][n];
int count = 1;
int sum = 0;
int loop = n/2;
while(loop > 0){
int one = sum;
int two = sum;
while(two < n-1-sum){
nums[one][two] = count;
two++;
count++;
}
while(one < n-1-sum){
nums[one][two] = count;
one++;
count++;
}
while(two > 0+sum){
nums[one][two] = count;
two--;
count++;
}
while(one > 0+sum){
nums[one][two] = count;
one--;
count++;
}
sum++;
loop--;
}
if(n%2 == 1){
nums[n/2][n/2] = n*n;
}
return nums;
}
}
出现的问题(快反思)
- 这里switch的每条分支都是要顺序执行的,所以根本不用写switch,直接写要执行的语句就行了
- 判断条件:怎么及时地让count>n*n的时候及时停止:参考做法是按圈数判断的
- while(0)为假,不会执行,其他非零数均为真。(我一直把0记成-1了)(并且java中while里不能直接填常量)
- 自减运算符只能应用于变量,而不是直接应用于表达式。
- 在Java中,while循环的条件必须是一个布尔表达式,但是你使用了loop–,这是一个赋值表达式,它返回的是原始值(在自减之前)而不是布尔值。
3.2.2 参考做法
- 每画一条边都要坚持一致的左闭右开,或者左开右闭的原则,这样这一圈才能按照统一的规则画下来。
- 循环要转n/2圈(一圈占两行,n是奇数的话,那就只剩最内圈也就是中心一个数,直接赋值n的平方就行)
class Solution {
public int[][] generateMatrix(int n) {
int[][] nums = new int[n][n];
int startX = 0, startY = 0; // 每一圈的起始点
int offset = 1;// 需要控制每一条边遍历的长度,每次循环右边界收缩一位
int count = 1; // 矩阵中需要填写的数字
int loop = 1; // 记录当前的圈数
int i, j; // j 代表列, i 代表行;
while (loop <= n / 2) {
// 顶部
// 左闭右开,所以判断循环结束时, j 不能等于 n - offset
for (j = startY; j < n - offset; j++) {
nums[startX][j] = count++;
}
// 右列
// 左闭右开,所以判断循环结束时, i 不能等于 n - offset
for (i = startX; i < n - offset; i++) {
nums[i][j] = count++;
}
// 底部
// 左闭右开,所以判断循环结束时, j != startY
for (; j > startY; j--) {
nums[i][j] = count++;
}
// 左列
// 左闭右开,所以判断循环结束时, i != startX
for (; i > startX; i--) {
nums[i][j] = count++;
}
startX++;
startY++;
offset++;
loop++;
}
if (n % 2 == 1) { // n 为奇数时,单独处理矩阵中心的值
nums[startX][startY] = count;
}
return nums;
}
}
4.总结
977:你是真菜啊,必须把排序学一遍,然后会代码,977找不到循环终止条件的时候,想着暴力解法写出来算了,然后发现自己不会写排序算法。(微笑)
59:一开始自己做的虽然知道很繁琐,空间复杂度高了,但是时间复杂度和参考的一样,一个会超时一个不会超时,所以力扣的时间限制应该蛮严格的。
今天:虽说三道题没一道顺利提交的,还做了很久。但是最起码都有思路,也是看到了一点点希望。