1.有序数组的平方
题目
给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。
示例 1:
-
输入:nums = [-4,-1,0,3,10]
-
输出:[0,1,9,16,100]
-
解释:平方后,数组变为 [16,1,0,9,100],排序后,数组变为 [0,1,9,16,100]
示例 2:
-
输入:nums = [-7,-3,2,3,11]
-
输出:[4,9,9,49,121]
注意点
-
题目给的数组是有顺序的,问题出在可能存在负数,负数平方之后可能变成最大的,就会导致数组顺序被打乱
-
负数平方之后可能变成最大值,但因为原来的数组有序,所以平方之后最大元素一定是在两边
-
例如{-3,1,2,3,4}或者{-5,-3,1,2,3,4}
-
双指针思路
思路
-
定义双指针从两头向中间取,也就是将数组中的数从大到小取出来.
伪代码
int[] result//创建一个新的数组来装结果 //定义一个索引下标 //因为我们取数是从大到小,但是题目要求按照递增排序,所以索引从大到小更新 k = numsize -1//numsize是原来数组的长度 for(i=0,j=numsize-1;i<=j;){//i++和j--是不能写在循环条件里的.因为i++和j--是取决于谁取到最大值,才发生变化,而不是每次循环都发生变化 if(num[i]*num[i]>=num[j]*num[j]){//num[i]表示原来数组中索引为i的元素 result[k] = num[i]*num[i];//把最大值放在新数组中的最后一位上 k--;//新数组的索引减小 i++;//因为i取到了最大值,所以i发生变化,j不动 }else{ result[k] = num[j]*num[j];//把最大值放在新数组中的最后一位上 k--;//新数组的索引减小 j--;//因为i取到了最大值,所以i发生变化,j不动 } } return result;
JAVA解法
public static int[] arrRank(int[] nums) { //1.创建一个新的数组存储结果 //不知道存储的结果用动态初始化 int[] result = new int[nums.length]; //2.创建双指针 int leftIndex = 0; int rightIndex = nums.length - 1; //3.创建新的数组的索引 int k = nums.length - 1; //3.遍历数组 while (leftIndex <= rightIndex) { if (nums[leftIndex] * nums[leftIndex] >= nums[rightIndex] * nums[rightIndex]) { result[k] = nums[leftIndex] * nums[leftIndex]; k--; leftIndex++; } else { result[k] = nums[rightIndex] * nums[rightIndex] k--; rightIndex--; } } return result; }
时间复杂度为O(n).
2.长度最小的数组
题目
给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的 连续 子数组,并返回其长度。如果不存在符合条件的子数组,返回 0。
示例:
-
输入:s = 7, nums = [2,3,1,2,4,3]
-
输出:2
-
解释:子数组 [4,3] 是该条件下的长度最小的子数组
注意点
-
循环里的索引表示的是终止位置
伪代码
int i = 0; int sum = 0; int result = max; for(j=0;j<=numsize;j++){ sum = sum + num[j]; while(sum>=s){ subL = j - i + 1;//滑动窗口的长度 //不断更新找出最小的 result = min(result,subL) sum = sum - num[i];//起始位置移动要把第一个位置的元素减去 i++;//起始位置移动 } return result; }
JAVA解法
public int minSubArrayLen(int target, int[] nums) { int startIndex = 0; int sum = 0; int result = Integer.MAX_VALUE;//拿出最大的数 for (int endIndex = 0; endIndex < nums.length; endIndex++) { sum = sum + nums[endIndex]; while (sum >= target){ int arrLength = endIndex - startIndex + 1; result = Math.min(result,arrLength); //startIndex=0时,已经找到满足条件了最小的长度,那么就把startIndex=0上的元素减去,继续寻找满足要求的集合长度 sum = sum - nums[startIndex]; startIndex++; } } return result == Integer.MAX_VALUE ? 0 : result; }
3.螺旋矩阵
题目
给定一个正整数 n,生成一个包含 1 到 n^2 所有元素,且元素按顺时针顺序螺旋排列的正方形矩阵。
示例:
输入: 3 输出: [ [ 1, 2, 3 ], [ 8, 9, 4 ], [ 7, 6, 5 ] ]
注意点
-
处理边界问题
思路
解本题依然是要坚持循环不变量原则。
模拟顺时针画矩阵的过程:
-
填充上行从左到右
-
填充右列从上到下
-
填充下行从右到左
-
填充左列从下到上
由外向内一圈一圈这么画下去。
这里一圈下来,我们要画每四条边,这四条边怎么画,每画一条边都要坚持一致的左闭右开,或者左开右闭的原则,这样这一圈才能按照统一的规则画下来。
JAVA代码
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; }