Day02算法| 977.有序数组的平方 ,209.长度最小的子数组 ,59.螺旋矩阵II

有序数组的平方

 同上篇一致运用双指针法

原理:

数组其实是有序的, 只不过负数平方之后可能成为最大数了。

那么数组平方的最大值就在数组的两端,不是最左边就是最右边,不可能是中间。

此时可以考虑双指针法了,left 指向起始位置,right 指向终止位置。

每次比较两个指针对应的数,选择较大的那个逆序放入答案并移动指针。这种方法无需处理某一指针移动至边界的情况

class Solution {
    public int[] sortedSquares(int[] nums) {
    	int left=0;
    	int right=nums.length-1;
    	int[] a=new int[nums.length];//a是平方后存储的数组
    	for(int k=nums.length-1;k>=0;k--) {
    		//两端的平方值比较大小,同时移动指针
    		int i=nums[left]*nums[left];
    		int j=nums[right]*nums[right];
    		if(i>j) {
    			a[k]=i;
    			left++;
    		}
    		else {
    			a[k]=j;
    			right--;
    		}
    	}
    	return a;
    }
}

长度最小的子数组

滑动窗口:

所谓滑动窗口,就是不断的调节子序列的起始位置和终止位置,从而得出我们要想的结果

定义两个指针 start和 end 分别表示子数组(滑动窗口窗口)的开始位置和结束位置,维护变量 sum存储子数组中的元素和。

类似这种:

初始做法:

class Solution {
    public int minSubArrayLen(int target, int[] nums) {
    	int n=nums.length-1;
    	int i=0,j=0,l=0,sum=nums[0];
    	while(i<=j){
    		if(sum<target&&j<n)
    		{
    			j++;
    			sum+=nums[j];
    		}
    		else if(sum>=target) {
    			if(l>j-i+1||l==0) {
    				l=j-i+1;
    			}
    			sum-=nums[i];
    			i++;
    		}
    		else {
				break;
			}
    	}
    	return l;
    }
}

利用 i 和 j 互相追逐特性设计循环,大致思想当总和超过时记录长度并移动 i ,总和小于时移动 j 扩展窗口,缺点是 i 与 j 容易越界,需多加条件作为限制。

参考代码:

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;
    }
}

改进:

1.将长度 l 定义为最大值(Integer.MAX_VALUE),返回值时进行是否为最大值的判断,可以在循环中减少一层判断

2.运用已有函数Math.min(),省去一层if判断:

if(l>j-i+1||l==0) {
   l=j-i+1;
 }

改为

l=Math.min(l, j-i+1);

3.总体思想是将窗口右指针移动作为循环条件,每一轮迭代,将 nums[right]加到 sum,如果 sum≥s,则更新子数组的最小长度(此时子数组的长度是 right−left+1),然后将 nums[left]从 sum中减去并将 left右移,直到 sum<s,在此过程中同样更新子数组的最小长度。在每一轮迭代的最后,将right右移。

可以发现滑动窗口的精妙之处在于根据当前子序列和大小的情况,不断调节子序列的起始位置。从而将O(n^2)暴力解法降为O(n)。


螺旋矩阵II

 自己想的:

思路:

每一圈为一个循环,每个颜色地块总数为第二层循环,即每个地块总数的数量一致情况下,

通过计算每个地块位置及其数值进行赋值

另奇数矩阵需要单独对中心进行赋值。

class Solution {
    public int[][] generateMatrix(int n) {
    	int[][] a=new int[n][n];
    	int sum=0;
    	for(int i=0;i<(n+1)/2;i++) {
    		int j=n-1-2*i;
    		for(int k=0;k<j;k++) {
    			a[i][i+k]=0*j+1+k+sum;
    			a[i+k][n-i-1]=1*j+1+k+sum;
    			a[n-i-1][n-i-k-1]=2*j+1+k+sum;
    			a[n-k-i-1][i]=3*j+1+k+sum;
    		}
    		sum+=4*j;
    	}
    	if(n%2!=0) {
    		a[n/2][n/2]=n*n;
    	}
    	return a;
    }
}

参考答案:

class Solution {
    public int[][] generateMatrix(int n) {
        int loop = 0;  // 控制循环次数
        int[][] res = new int[n][n];
        int start = 0;  // 每次循环的开始点(start, start)
        int count = 1;  // 定义填充数字
        int i, j;

        while (loop++ < n / 2) { // 判断边界后,loop从1开始
            // 模拟上侧从左到右
            for (j = start; j < n - loop; j++) {
                res[start][j] = count++;
            }

            // 模拟右侧从上到下
            for (i = start; i < n - loop; i++) {
                res[i][j] = count++;
            }

            // 模拟下侧从右到左
            for (; j >= loop; j--) {
                res[i][j] = count++;
            }

            // 模拟左侧从下到上
            for (; i >= loop; i--) {
                res[i][j] = count++;
            }
            start++;
        }

        if (n % 2 == 1) {
            res[start][start] = count;
        }

        return res;
    }
}

小技巧:

1.int最大值:Integer.MAX_VALUE,可以在变量不适合赋值0时进行赋值

2.遍历二维数组:

for(int i=0;i<n;i++) {
			System.out.println(Arrays.toString(key[i]));
		}

3.获取绝对值:Math.abs();

4.判断奇数偶数:

if (number%2==0){
            System.out.println(number+"是偶数");
        }else {
            System.out.println(number+"是奇数");
        }

  • 26
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值