文章目录
双指针
977 有序数组平方
- 暴力 冒泡排序 o(n^2)
class Solution {
public int[] sortedSquares(int[] nums) {
int size = nums.length;
for(int i=0;i<size;i++){
nums[i]=nums[i]*nums[i];
}
for(int i=0;i<size-1;i++){
for(int j=i+1;j<size;j++){
if(nums[i]>nums[j]){
int t=nums[i];
nums[i]=nums[j];
nums[j]=t;
}
}
}
return nums;
}
}
-
双指针
数组其实是有序的, 只不过负数平方之后可能成为最大数了。那么数组平方的最大值就在数组的两端,不是最左边就是最右边,不可能是中间。
此时可以考虑双指针法了,i指向起始位置,j指向终止位置。
则双指针指向的两侧元素开始比较大小,并把大的数值赋给新数组的最后一个位置,新数组向前移动一位。如果是i的平方比j的平方大,那么i++,i的后一个位置和j再进行比较。定义一个新数组result,和A数组一样的大小,让k指向result数组终止位置。
如果A[i] * A[i] < A[j] * A[j] 那么result[k–] = A[j] * A[j]; 。
如果A[i] * A[i] >= A[j] * A[j] 那么result[k–] = A[i] * A[i]; 。
ps:
result[k–] = A[j] * A[j];和result[k] = A[j] * A[j];k–等价。
class Solution {
public int[] sortedSquares(int[] nums) {
int size=nums.length;
int[] result = new int[size];
int left=0,right=size-1;
int index = size-1;
while(left<=right){
if(nums[left]*nums[left]>nums[right]*nums[right]){
result[index--]=nums[left]*nums[left];
left++;
}else{
result[index--]=nums[right]*nums[right];
right--;
}
}
return result;
}
}
125 验证回文串
class Solution {
public boolean isPalindrome(String s) {
StringBuffer sgood = new StringBuffer();
//StringBuffer 对象,用于存储提取出来的字母和数字。StringBuffer 是一个可变的字符串类,用于在处理字符序列时更高效。
int len = s.length();
for(int i = 0 ;i<len;i++){
char ch = s.charAt(i);//获取字符串中索引为 i 的字符。
if(Character.isLetterOrDigit(ch)){
sgood.append(Character.toLowerCase(ch));
//如果是字母,将其转换为小写形式,并追加到 sgood 中。
}
}
int l=0,r=sgood.length()-1;
while(l<r){
if(sgood.charAt(l)!=sgood.charAt(r)){
return false;
}
l++;
r--;
}
return true;
}
}
滑动窗口
209.长度最小的子数组
只用一个for循环,那么这个循环的索引,一定是表示 滑动窗口的终止位置。
其实从动画中可以发现滑动窗口也可以理解为双指针法的一种!只不过这种解法更像是一个窗口的移动,所以叫做滑动窗口更适合一些。
在本题中实现滑动窗口,主要确定如下三点:
- 窗口内是什么?
- 如何移动窗口的起始位置?
- 如何移动窗口的结束位置?
窗口就是 满足其和 ≥ s 的长度最小的 连续 子数组。
窗口的起始位置如何移动:如果当前窗口的值大于s了,窗口就要向前移动了(也就是该缩小了)。
窗口的结束位置如何移动:窗口的结束位置就是遍历数组的指针,也就是for循环里的索引。
解题的关键在于 窗口的起始位置如何移动,如图所示:
可以发现滑动窗口的精妙之处在于根据当前子序列和大小的情况,不断调节子序列的起始位置。从而将O(n^2)暴力解法降为O(n)。
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int left = 0; // 滑动窗口起始位置
int sum = 0; // 滑动窗口数值之和
// int result = Integer.MAX_VALUE;
int result = Integer.MAX_VALUE;
for(int right=0;right<nums.length;right++){
// sum+=nums[left]+nums[right];
sum+=nums[right]; //加进来新的窗口的值,去判断是否达到或超过target
// 注意这里使用while,每次更新 i(起始位置),并不断比较子序列是否符合条件
while(sum>=target){
result = Math.min(result,right-left+1);//更新最小值
// left++;
sum-=nums[left++];// 这里体现出滑动窗口的精髓之处,不断变更i(子序列的起始位置)
}
}
// 如果result没有被赋值的话,就返回0,说明没有符合条件的子序列
return result==Integer.MAX_VALUE?0:result;
}
}
904 水果成篮-滑动窗口求最长子数组!
class Solution {
public int totalFruit(int[] fruits) {
int n=fruits.length;
Map<Integer,Integer>cnt=new HashMap<Integer,Integer>();
int left=0,ans=0;
for(int right=0;right<n;right++){
cnt.put(fruits[right],cnt.getOrDefault(fruits[right],0)+1);// 更新key的值,也就是水果种类出现的次数
// cnt.getOrDefault(fruits[right], 0) 从 cnt 中获取键为 fruits[right] 的值,如果该键不存在,则返回默认值 0
while(cnt.size()>2){
cnt.put(fruits[left],cnt.get(fruits[left])-1);
if(cnt.get(fruits[left])==0){
// 如果是0,表示该水果在窗口中不再存在,需要将其从 cnt 中移除。
cnt.remove(fruits[left]);
}
left++;
}
ans = Math.max(ans,right-left+1);
}
return ans;
}
}
76.最小覆盖子串(没做)
螺旋矩阵(转圈)
59. 螺旋矩阵 II
b,t代表行,l,r代表列。t,l小,b,r大
class Solution {
public int[][] generateMatrix(int n) {
int l=0,r=n-1,t=0,b=n-1;
int[][] mat = new int[n][n];
int num=1,tar=n*n;
while(num<=tar){
for(int i=l;i<=r;i++){
mat[t][i]=num++;//left->right
// t++;
}
t++;
for(int i=t;i<=b;i++){
// mat[l][i]=num++;//top->bottom
// l++;
mat[i][r]=num++;//top->bottom
// r--;
}
r--;
for(int i=r;i>=l;i--){
mat[b][i]=num++;//right->left
// b--;
}
b--;
for(int i=b;i>=t;i--){
mat[i][l]=num++;//bottom->top
// l++;
}
l++;
}
return mat;
}
}
54.螺旋矩阵
class Solution {
public List<Integer> spiralOrder(int[][] matrix) {
int m = matrix.length;//行数
int n = matrix[0].length;//列数
List<Integer> res = new ArrayList<>();
int l=0,r=n-1,t=0,b=m-1;
// int num=1,tar=m*n;
while(true){
for(int i=l;i<=r;i++){
res.add(matrix[t][i]);
}
// t++;
if(++t>b)break;//判断边界,注意在if中++t t的数值依旧会变化
for(int i=t;i<=b;i++){
res.add(matrix[i][r]);
}
// r--;
if(--r<l)break;
for(int i=r;i>=l;i--){
res.add(matrix[b][i]);
}
if(--b<t)break;
for(int i=b;i>=t;i--){
res.add(matrix[i][l]);
}
if(++l>r)break;
}
return res;
}
}
剑指offer 146螺旋遍历二维数组
class Solution {
public int[] spiralArray(int[][] array) {
// 矩阵为0的情况没有考虑
if(array.length == 0) return new int[0];
int m = array.length;//行数
int n = array[0].length;//列数
int idx=0;
int[] res = new int[m*n]; //List<Integer>和int数组的处理方式不同
// int[]res需要设置index依次填充 List=ArrayList<>()可以直接add元素
int l=0,r=n-1,t=0,b=m-1;
// int num=1,tar=m*n;
while(true){
for(int i=l;i<=r;i++){
res[idx++]=array[t][i];
}
// t++;
if(++t>b)break;
for(int i=t;i<=b;i++){
res[idx++]=array[i][r];
}
// r--;
if(--r<l)break;
for(int i=r;i>=l;i--){
res[idx++]=array[b][i];
}
if(--b<t)break;
for(int i=b;i>=t;i--){
res[idx++]=array[i][l];
}
if(++l>r)break;
}
return res;
}
}