LeedCode 977 有序数组的平方
给你一个按非递减顺序排序的整数数组 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]
寻找关键信息:
- 是一个非递减的整数数组 => 顺序数组
- 返回的是最后新数组的变量名 => 需要准备新的存储数组
解题环节
方法1:暴力解法
解题思路:把所有元素存储到新数组中 ,调用Arrays.sort进行排序,此处的时间复杂度,取决于排序的方式,在这里是 O(nLogn)
public class SortedSquared_ {
//暴力解法:全部存储到数组中,调用方法类Arrays.sort进行排序
public static int[] Squared(int []nums){
int[] ans = new int[nums.length];//存储的数组
for (int i = 0; i < nums.length; ++i) {
//此处i需要提前++
ans[i] = nums[i]*nums[i];
//所有数的平方存入数组中
}
Arrays.sort(ans);//调用排序方法进行排序
return ans;//返回存储数据数组
}
}
方法2:双指针法
解题思路:在头尾插入一个指针right、left,如果右边边界数值的平方 < 左边边界数值的平方,说明左边的是负数(题目给出的是顺序数组),存入存储数组的最右边即可,反之,如果左边的边界数值的平方 <= 右边边界数值的平方(相等可以加进去,因为加谁都是一样,这里算到右边的边界数值上) 这里加入存储数组的数就是右边的数值
public class SortedSquared {
public static int[] Squared(int nums[]){
int left = 0;//设定初始数组区间值
int right = nums.length;
int []result = new int[nums.length];//存储数组
int index = nums.length - 1;//数组元素数量
while(left <= right){
//两边区间值可作为循环条件存在
if(nums[left] * nums[left] <= nums[right] * nums[right]){
result[index--] = nums[right] *nums[right];//存储数组下标为nums数组长度-1,存了东西需要减少
--right;//右侧下标减少,不减少的话,会一直在原地,变成死循环
}else if ( nums[left]*nums[left]>nums[right]*nums[right]){
result[index--] = nums[left]*nums[left];//index减少原理同上,
//此时是左边的区间值,进入当前条件之后,需要向右边区间进行推进,保证所有元素都判断和操作过
++left;
}
}
return result;
}
}
LeedCode 209 长度最小的子数组
给定一个含有 n
个正整数的数组和一个正整数 target
。
找出该数组中满足其和 ≥ target
的长度最小的 连续子数组 [numsl, numsl+1, ..., numsr-1, numsr]
,并返回其长度。如果不存在符合条件的子数组,返回 0
。
题意归纳:在一段数组中,找出 数组中组合数 >= targer 的组合数组最小长度(全部都是正整数)
解法1:暴力解法
循环两次,一次用于遍历元素,一遍负责计算数组中数字相加部分
时间复杂度:遍历两次,O(n2)
public static int minSubArrayLen(int s, int[] nums) {
int n = nums.length;//获取nums长度
if (n == 0) {
return 0;//长度为0(没有数据) ---返回0
}
int ans = Integer.MAX_VALUE;//存储数组下标,为int最大值2147483647
//枚举数组nums i为开始下标
for (int i = 0; i < n; i++) {
int sum = 0;//相加总和变量
for (int j = i; j < n; j++) {
sum += nums[j];//加入数字,判断数组数字和是否大于给定数字
if (sum >= s) {//判断是否大于给定的数字
ans = Math.min(ans, j - i + 1);
//j-i+i为相加大于给定数字的数组长度(题目要求返回的也是数组长度)
//Math.min --返回计算小的那个数字
break;//找到了大于等于给定数字,跳出当前循环
}
}
}
return ans == Integer.MAX_VALUE ? 0 : ans;
//三目运算符,判断给定数组下标是否改变,
//未改变(没有找到大于给定数的数据存在)
//改变了(找到了大于等于给定数据,返回最小数组的值)
}
解法2:滑动窗口
核心思想:给出两个指针,一根在数组上方进行遍历数字操作,一根指针在下方负责判断,若出现大于给定值的节点出现,保存当前数组长度(出现了比当前数组长度小的替换),上下会因为条件指针的长度会出现变化,故称为滑动窗口。
时间复杂度:由于遍历只需要一轮,复杂度为O(n)
public static int minSubArrayLen(int s, int[] nums) {
int n = nums.length;//获取nums长度
if (n == 0) {
return 0;//长度为0(没有数据) ---返回0
}
int ans = Integer.MAX_VALUE;//存储数组下标,为int最大值2147483647
//暴力节点不同部分
int start = 0,end = 0;//定义两个指针
int sum = 0;//定义一个维护遍历
while(end < n){
//先对比上方end指针,初始位置在end上,n是总数组的长度
sum += nums[end];
//sum = sum +nums[end];
while(sum >= s){
//若当前数值 >= 给定数值
ans = Math.min(ans,end - start + 1);//找出最小数组长度
sum -= nums[start];//减去下方指针指向的第start个元素
start++;//下方指针向前移动一位
}
end++;//上方指针移动
}
return ans == Integer.MAX_VALUE ? 0 : ans;
//三目运算符,判断给定数组下标是否改变,
//未改变(没有找到大于给定数的数据存在)
//改变了(找到了大于等于给定数据,返回最小数组的值)
}
LeedCode 59 螺旋矩阵
给你一个正整数 n
,生成一个包含 1
到 n2
所有元素,且元素按顺时针顺序螺旋排列的 n x n
正方形矩阵 matrix
。
示例 1:
输入:n = 3
输出:[[1,2,3],[8,9,4],[7,6,5]]
输入:n = 1
输出:[[1]]
解题思路:一开始我在看这道题的时候,第一种感觉就是复杂,在这里对题目进行拆解,同时找到规律是解题的关键之一,还有一个非常关键的点在于我们每一次循环的时候选择遍历的区间,也就是卡哥所说的循环不变量,这一点是我们需要确定的一个问题。满足每次循环为固定量,并且出错很少的,就是左闭右开原则 [x,x),也就是说最后一个点不是在第一次就取到,而是放进下一次小循环中,这样保持循环不变量,很容易成功!!!
public static 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){//判断边界调节
// 模拟上侧从左到右
for (j = start; j < n - loop; j++) {
res[start][j] = count++;
// loop用于控制循环的次数
// start代表每次的起点,作为第一行的二维数组的存储坐标
// count代表矩阵中填充的数字
// 填充规则,左闭右开,也就是说每次循环填充的数据是给定数据n-1(不包括即将向下遍历循环的这个点)
// 四条边都遵循这个原则,不然思路容易混乱(循环不变量需要一开始就确定清楚!!!)
// 1 2 3 4 5 切记,为什么6不取,左闭右开原则,循环不变量原则(取的数字数量是给 定数数字 -1)
}
// 模拟右侧从上到下
for (i = start; i < n - loop; i++) {
res[i][j] = count++;
/*
此处为第二组遍历循环数据,由于是从上往下,所以这里的遍历变化量是i
1 2 3 4 5 6
7
8
9
这里取到得数和第一次取到的数是一样的
*/
}
// 模拟下侧从右到左
for (; j >= loop; j--) {
res[i][j] = count++;
/*
此处为第三组遍历循环数据,由于是从下方的后段到前段( <---- ),所以这里的遍历变化量是j
1 2 3 4 5 6
7
8
9
14 13 12 11 10
这里取到的数是不包括15的(左闭右开---循环不变量原则)
*/
}
// 模拟左侧从下到上
for (; i >= loop; i--) {
res[i][j] = count++;
/*
此处为第四组遍历循环数据,由于是从下方的前段段到上方的上段( ),所以这里的遍历变化量是j
1 2 3 4 5 6
20 7
19 8
18 9
17 10
16 15 14 13 12 11
这样,一个大循环就完成了,也没有出现纰漏的情况
这样会进入第二段循环,而对于第二段,数组下标(横纵坐标)需要向前移动,
在三、四小循环的时候,我们对于i和j进行了数值的还原,这样的好处,对于我们第二个大循环又可以照常使用了
而每多一次大循环,横向遍历的数据就会减少1,这里我们使用了大循环条件中的loop进行控制,当前大循环
开始,下一次开始数值就发生了变化---设计很精妙
*/
}
start++;
}
if (n % 2 == 1) {
res[start][start] = count;//指定中间的那个数字
//当指定的n*n矩阵的n为基数的时候,在最后一个元素加入数组的时候,会进入当前判断,
//如果是偶数的话,会在上面的第四个循环内,添加到数组的操作就结束了
}
return res;
}
这道题如果在面试中遇到了,希望大家不要着急,还是需要按照循环不变量的方式,一步一步找思路,一定可以成功的!!!