977.有序数组的平方
思路一:数组数据是非递减,那么平方后,两个端点比较会得出一个最大值,那么将最大值放在新数组中,端点减一或加一,再次比较拿出新的最大值,直到两个端点重合(或者新数组填满)即可
public int[] sortedSquares(int[] nums) {
if (nums.length == 0) {
return nums;
}
int[] newNums = new int[nums.length];
int left = 0;
int right = nums.length -1;
int point = newNums.length -1;
while (point>=0) {
if (nums[left] * nums[left] > nums[right] * nums[right]) {
newNums[point--] = nums[left] * nums[left];
left++;
} else {
newNums[point--] = nums[right] * nums[right];
right--;
}
}
return newNums;
}
思路二:找出数组中负数绝对值最小的索引,分为两组数据。一组为[0,negative]为单调递减的、一组为[negative+1,nums.length -1]。然后比较两组数据中的最小值填入新数组中即可。跳出循环条件为新数组填满或negative达到最左边或者negative+1达到最右边
public int[] sortedSquares(int[] nums) {
if (nums.length == 0) {
return nums;
}
int negative = 0;
for (int i = 0; i < nums.length; i++) {
if (nums[i] < 0) {
negative = i;
} else {
break;
}
}
int[] ints = new int[nums.length];
int index = 0;
int noNegative = negative + 1;
//while(negative>=0 || noNegative< nums.length)
while (index < nums.length) {
if (negative < 0) {
ints[index] = nums[noNegative] * nums[noNegative];
noNegative++;
} else if (noNegative == nums.length) {
ints[index] = nums[negative] * nums[negative];
negative--;
}else if (Math.abs(nums[negative]) < nums[noNegative]) {
ints[index] = nums[negative] * nums[negative];
negative--;
} else if (Math.abs(nums[negative]) >= nums[noNegative]) {
ints[index] = nums[noNegative] * nums[noNegative];
noNegative++;
}
index++;
}
return ints;
}
209.长度最小的子数组
滑动窗口双指针解法:定义初始指针、终止指针,用resul记录子数组长度并初始为int.MAX。当两个指针区间的元素之和大于等于目标值时,则和减去初始指针元素并自增,然后再对比。直到终止指针达到最右,最后返回result即可。
public int minSubArrayLen(int target, 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 >= target) {
result = Math.min(result, right - left + 1);
sum -= nums[left++];
}
}
return result == Integer.MAX_VALUE ? 0 : result;*/
int left = 0, right = 0, sum = 0, result = Integer.MAX_VALUE;
while (right < nums.length) {
sum += nums[right++];
while (sum >= target) {
result = Math.min(result, right - left);
sum -= nums[left++];
}
}
return result == Integer.MAX_VALUE ? 0 : result;
}
二分查找 + 前缀:
1、使用一个新数组记录前面元素之和,例如prefix[1] = 原数组的第一个元素之和,prefix[2] = 原数组的1、2元素之和,依次类推。所以前缀数组的长度比原数组长度大于1。
2、遍历前缀数组,当前元素 + target值 <= 二分查找的值(prefix[j] - prefix[i] >= target)
3、在前缀数组中使用二分查找大于等于 当前元素 + target值 的索引位置,找到会返回索引,找不到会返回大于目标值的第一个索引。
4、将二分查找的返回的索引 - 当前元素索引 = 子数组长度
public int minSubArrayLen(int target, int[] nums) {
int result = Integer.MAX_VALUE;
int[] prefix = new int[nums.length + 1];
for (int i = 1; i < prefix.length; i++) {
prefix[i] = prefix[i-1] + nums[i-1];
}
for (int i = 0; i < prefix.length; i++) {
int sum = target + prefix[i];
int index = Arrays.binarySearch(prefix, sum);
if (index < 0){
index = ~index;
}
if (index < prefix.length){
result = Math.min(result,index - i);
}
}
return result == Integer.MAX_VALUE ? 0 :result;
}
59.螺旋矩阵II
思路:找出循环不变量和循环条件,再填入元素即可,输入为奇数时,填入最后一个元素即可
public int[][] generateMatrix(int n) {
int count = 1, startX = 0, startY = 0, x, y;
int[][] ints = new int[n][n];
for (int i = 0; i < n / 2; i++) {
for (y = startY; y < n - 1 - startY; y++) {
ints[startX][y] = count++;
}
for (x = startX; x < n - 1 - startX; x++) {
ints[x][y] = count++;
}
for (; y > startY; y--) {
ints[x][y] = count++;
}
for (; x > startX; x--) {
ints[x][y] = count++;
}
startX++;
startY++;
}
if (n % 2 == 1) {
ints[startX][startY] = count;
}
return ints;
}
心得:
1、977.有序数组的平方回归到数学问题,使用单调性或双端最大值解决该问题
2、209.长度最小的子数组使用滑动窗口时,找出起始点、终止点与窗口(刚开始没思路,只想到暴力解题),使用前缀法+二分查找需要了解二分查找找不到返回的是比目标值大一位的位置,还不够深刻。
3、59.螺旋矩阵II,刚开始只满足外层循环,内部循环遇到各种问题,还是看解题思路有才明确循环不变量及循环条件,就容易做出来了