有序数组的平方
例子
-5,1,2,3
双指针思路
最大元素一定是在两边,不可能在中间找到最大的元素,因为负数平方后有可能成为最大一个值使用两个指针的一个操作而逐步向中间合拢的过程,来得到一个有大到小的数组,但是这道题目是输出一个由小到大的一个元素的集合其实在更新新的数组时,这个新的数组下标就由大到小来进行更新就可以了,这样就可以得到新的数组,这个数组就是原始数组的所有元素平方之后的一个有序数组
代码具体实现
先定义一个新数组,新的数组装平方之后新的元素
代码如下:
class Solution {
public int[] sortedSquares(int[] nums) {
int[] result = new int[nums.length];
int left = 0;
int right = nums.length - 1;
int k = nums.length - 1;
while(left <= right){
if(nums[left] * nums[left] > nums[right] * nums[right]){
result[k] = nums[left] * nums[left];
k--;
left++;
}else{
result[k] = nums[right] * nums[right];
k--;
right--;
}
}
return result;
}
}
第二思路
1、假设i表示的是起始位置,如果i表示的是起始位置,这个for循环一次一次的把下标索引像右边移动的话,这个终止位置要如何去遍历?起始位置如果在左边,终止位置也要把后面的所有元素都遍历一遍,才能返回以i为起始位置的集合然后去判断这个集合里面的所有元素,如果>=s的
话,就去收集>=s 这些集合的,所有长度最小的一个
2、for循环里面的i一定指向的是终止位置,而起始位置需要一个动态移动的策略来去移动起始位置,这样才能用一个for循环的思路来解决这道题目,滑动窗口精华所在,for循环的i明确了,它是指向滑动窗口里边的终止
位置
3、如果终止位置指向第二个2,这个集合里边的元素>=s 的话,说明这是符合条件的一个集合,收集他的长度之后,这个起始位置就可以向右边移动了,这样来缩小目前的集合,来看下一个集合是否符合我们的这个条件,当发现集合里面的所有元素和> = s的时候,再去移动起始位置就可以动态的去调整起始位置,来去收集不同区间里边的和,不同长度区间里边的和
代码实现
1、从0开始i<=nums.sizej++,然后开始收集终止位置所指向的元素,因为要有一个集合,这个集合要用集合里边的元素来和这个s做判断,sum就是把这个滑动窗口里边的元素的和sun+= nums[j] 这个sum收集滑动窗口里边的和,终止位置是一个一个向后移动,这个sum不断去收集,直到收集的这个和>=s 了 if(sum>=s)此时是符合要收集的这个滑动窗口长度的条件,因为是要取这个元素和大于等于s的最小长度当if(sum>=s)这个滑动窗口的长度
2、result起始值要为最大值max,因为只有是最大值,才
能去不断更新取所有subl里边的最小值 subl=i-i+1这个i是起始位置,收集完长度后,要有一个result,result收集最终最小的长度和收集subl取的最小值,result = min(result,subl) 这样result才能持续更新符合总和>=s里边的最小长度,收集完之后,开始移动起始位置sum = sum- nums[i]
3、移动起始位置的时候,向右边移动,sum要减去numbers目前起始位置的值,因为起始位置要向后移动了,那sum是表示滑动窗口里边的所有元素的一个集合,起始位置向后移动之后,和应该把这个目前numbers这个起始位置这个值给减下去,再做一个i--的操作
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int left = 0; // 终止指针
// 滑动指针 left
int result = Integer.MAX_VALUE;
int sum = 0;
for(int right = 0; right < nums.length; right++){
sum += nums[right];
while(sum >= target){
int subl = right - left + 1;
result = Math.min(result,subl);
sum = sum - nums[left];
left++;
}
}
return result == Integer.MAX_VALUE ? 0 : result;
}
}
第三题 螺旋矩阵
题目:
给定一个正整数n,生成一个包含1到n^2所有元素,且元素按顺时针顺序螺旋排列的正方形矩阵示例:
输入:3输出:[[1,2,3],[ 8,9,4],[7,6,5]
题目链接:59. 螺旋矩阵 II - 力扣(LeetCode)
难点:关键性的点,都在边界上,正方形4个点,都要考虑边界点怎么处理?
解答:循环不变了原则,循环不变量: 不变量其实是对每条边的一个处理规则,要坚持一个规则处理每一条边,使用左闭右开的规则来遍历
左上左闭右开只处理第一个节点,最后一个节点不处理,只处理一段,遍历下一条边也只处理一个节点,最后一个节点不处理,第三条也是,第四条处理第一个节点,最后那个不用处理,四条边的规则都统一了
解题思路:
先写循环部分,while循环,如果n是4,就返回4x4的大小矩阵,while(n /2),如果转一圈,左右都会少一条边,整个正方形的宽度减2,一共宽度是n,每次减2,就是循环n/2次
如果n是奇数的话,nums[][] = 所填充的数组,单独赋值,最后得值给他就可以了
进入循环,先编辑上边,循环不固定的,起始位置定义为startx= 0 start y=0
offset = 1
count=1 # 计数
for(j = start x j< n - offset j++)
终止位置不包含最后一个元素,如果n是四,那下标就是了了,小于的话,第一行遍历就包含3了
如何填充元素
numbers[statx]lj] = count ++ 第一条边遍历出来了
第二条
fori = start x i< n - offset i++)
填写元素
往下遍历的时候,i里边的终止条件是<n- offset了,此时循环结束之后,i已经等于= n - offset了i的这个值已经固定了,如果n等于4,那现在i就是了了numbersli][j] = count ++ 第二条遍历出来了
第三条
第三次改变的是i的值,此时这个i是n - offset 等于3了的,j的值不需要初始化了,i和j在这里是最大初始值要大于起始位置的点,因为不处理,最后这个点留给下一条处理,这样才符合左闭右开的原则
for(j > starty j- -)
赋值 numsli] [ij] = count++
第四条,最后一条
i初始值不需要变i便利到终止点前一个
for(i > starty i- -)
nums[i] [i] = count++ 最后再去转整个圈
每圈一圈的话,startx和starty,都要++,offset也要++,往里面索,如果n是奇数,对中间的元素
numsli] [j] = count
C++代码如下
class Solution {
public:
vector<vector<int>> generateMatrix(int n) {
vector<vector<int>> res(n, vector<int>(n, 0)); // 使用vector定义一个二维数组
int startx = 0, starty = 0; // 定义每循环一个圈的起始位置
int loop = n / 2;
// 每个圈循环几次,例如n为奇数3,那么loop = 1 只是循环一圈,矩阵中间的值需要单独处理
int mid = n / 2;
// 矩阵中间的位置,例如:n为3, 中间的位置就是(1,1),n为5,中间位置为(2, 2)
int count = 1; // 用来给矩阵中每一个空格赋值
int offset = 1; // 需要控制每一条边遍历的长度,每次循环右边界收缩一位
int i,j;
while (loop --) {
i = startx;
j = starty;
// 下面开始的四个for就是模拟转了一圈
// 模拟填充上行从左到右(左闭右开)
for (j = starty; j < n - offset; j++) {
res[startx][j] = count++;
}
// 模拟填充右列从上到下(左闭右开)
for (i = startx; i < n - offset; i++) {
res[i][j] = count++;
}
// 模拟填充下行从右到左(左闭右开)
for (; j > starty; j--) {
res[i][j] = count++;
}
// 模拟填充左列从下到上(左闭右开)
for (; i > startx; i--) {
res[i][j] = count++;
}
// 第二圈开始的时候,起始位置要各自加1, 例如:第一圈起始位置是(0, 0),第二圈起始位置是(1, 1)
startx++;
starty++;
// offset 控制每一圈里每一条边遍历的长度
offset += 1;
}
// 如果n为奇数的话,需要单独给矩阵最中间的位置赋值
if (n % 2) {
res[mid][mid] = count;
}
return res;
}
};
Java代码如下
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) {
// 检查边界条件,循环从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++;
}
// 如果n为奇数,填充中心元素
if (n % 2 == 1) {
res[start][start] = count;
}
return res;
}
}
解释一下loop++ < n / 2
整个条件 loop++ < n / 2
的含义是,当 loop
的值小于 n / 2
时,循环继续执行。这样设计是为了在每次循环迭代时逐渐向矩阵的中心移动,直到 loop
的值超过 n / 2
为止。符合在螺旋矩阵中向内层层逼近的逻辑
for (; j >= loop; j--)
这行是一个 for
循环的一部分,这里的冒号 :
表示空语句,即循环体为空。这样的写法是为了在 for
循环的头部声明变量 j
,然后在循环体内部执行语句 res[i][j] = count++
,最后通过 j--
来更新 j
的值。