算法:数组理论(二)
有序数组的平方
题目链接: leetcode#977
给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。
题目的前置条件为非递减顺序的有序数组,不难看出,平方后新数组的最大值必在数据的两侧,可以使用双指针的方法,分别指向数组两侧,进行大小比较,将平方后较大值的元素放到新数组末端(平方值从大往小的找),随后移动指针(移动平方结果大的指针,移动方向为靠近数组中间因为我们是从大往小的找),之后继续进行下一个最大值查找。
public int[] sortedSquares(int[] nums) {
int[] res = new int[nums.length]; // 返回结果
int left=0;// 左边指针
int right=nums.length-1; // 右边指针
int targetInsertIdx = res.length-1; //新数组需要添加的下标,从大往小找
while(left <= right) {
int leftVal = nums[left] * nums[left]; // 左指针对应的值
int rightVal = nums[right] * nums[right]; // 右指针对应的值
if (leftVal >= rightVal) {
res[targetInsertIdx] = leftVal; // 如果左边大,新数组赋值左指针向内部移动
left++;
} else {
res[targetInsertIdx] = rightVal; // 如果右边大,新数组赋值右指针向内部移动
right--;
}
targetInsertIdx--; // 需要插入的下标往前移动,因为后面的数据会逐步减小
}
return res;
}
长度最长子数组
题目链接: leetcode#209
给定一个含有 n 个正整数的数组和一个正整数 target 。 找出该数组中满足其总和大于等于 target 的长度最小的 子数组 [numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。
按照常规理解,我们只需要找到所有和>=s的子数组就可以,随后找到这些子数组中长度最小的,这需要我们枚举出所有的子数组,时间复杂度会很高() (for循环两次)
滑动窗口:如果我们在遍历数组的过程中,使用两个指针,两个之间的元素为我们需要观察的子数组,遍历时,可以不断调节两个指针使得子数组和满足>=s,这样我们只需要进行一次遍历即可
我们定义两个指针,左、右,如何调节指针?重新理一下题目,子数组和>=s&&最短子数组长度,由此,如果子数组和不满足条件,则子数组的元素需要增加,所以左指针不移动,右边指针移动,如果当前子数组和已经满足,因为我们要找最短的,所以碰到满足条件的,就可以尝试缩小子数组则左的指针往后移,随后重复上面的判断,继续往下找,就可以完成这道题目
public int minSubArrayLen(int target, int[] nums) {
int res = Integer.MAX_VALUE;
int left = 0; // 左
int right = 0; // 右
int sum = 0; // 子数组和
for (; right < nums.length; right++) {
sum += nums[right];
while (sum >= target) { // 尝试缩小滑动窗口
res = Math.min(res, (right-left+1));
sum -= nums[left++]; // 注意sum记得回退
}
}
return Objects.equals(Integer.MAX_VALUE, res) ? -0 : res;
}
螺旋矩阵 II
题目链接: leetcode#59
给你一个正整数 n ,生成一个包含 1 到 n2 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。
注意边界,选择左开右闭的方式
public int[][] generateMatrix(int n) {
int[][] nums = new int[n][n];
int loop = 1; // 记录循环层数
int i,j; // 下标
int count = 1; // 从1->n
int x = 0;
int y = 0;
while(loop <= n/2) {
for(j=y; j<n-loop; j++) { // n-loop注意边界
nums[x][j] = count++;// 左->右
}
for (i=x; i<n-loop; i++) { // n-loop注意边界
nums[i][j] = count++;// 上->下
}
for (; j>y; j--) { // 左闭
nums[i][j] = count++; // 右->左
}
for (; i>x; i--) {
nums[i][j] = count++;// 下->上
}
loop++;
x++;
y++;
}
// 如果n是单数,这中间位置需要特殊处理下
if(n % 2 == 1) {
nums[x][y] = count++;
}
return nums;
}