0
点赞
收藏
分享

微信扫一扫

数组+题目

mm_tang 2022-04-05 阅读 62

概述

  • 连续存储空间,存相同类型数据的集合
  • 二维数组内存空间
    在这里插入图片描述

二分查找

1.二分查找[704]

  • 前提:数组元素有序不重复
  • 时间复杂度:O(logn)
  • 注意
left与right边界取值情况

2.搜索插入位置[35]

  • 分析
    请添加图片描述
  • 暴力解法
时间复杂度:O(n)
------------------------
class Solution {
    public int searchInsert(int[] nums, int target) {
        for(int i=0;i<nums.length;i++){
            if(nums[i]>=target){
                return i;
            }
        }
        return nums.length;
    }
}
  • 二分法
class Solution {
    public int searchInsert(int[] nums, int target) {
        int left=0;
        int rigth = nums.length-1;
        int temp = nums.length;
        while(left<=rigth){
            int mid = (left+rigth)>>>1;
            if(nums[mid]>=target){
                temp = mid;
                rigth = mid-1;
            }else{
                left = mid+1;
            }
        }
        return temp;
    }
}
---------------------------------------------------
class Solution {
    public int searchInsert(int[] nums, int target) {
        int left = 0;
        int right = nums.length-1;
        int mid = 0;
        while(left<=right){
        	mid = (left+right)>>>1;
            if(target>nums[mid]){
            	left=mid+1;
            }else if(target<nums[mid]){
            	right=mid-1;
            }else{
            	return mid;
            }
        }
        return right+1;
    }
}

3.在排序数组中查找元素的第一个和最后一个位置[34]

  • 暴力解法
class Solution {
    public int[] searchRange(int[] nums, int target) {
        if(nums.length<=0) return new int[]{-1,-1};
		
		int start = -1;//保存第一个target位置
		for(int i=0;i<nums.length;i++){
			if(nums[i]==target){
				start=i;
				break;
			}
		}
		
        if(start==-1) return new int[]{-1,-1};
        
        for(int i=start;i<=nums.length;i++){
        	if(i==nums.length || nums[i]!=target){
        		return new int[]{start,i-1};
        	}
        }
        return new int[]{-1,-1};
    }
}
  • 二分法
class Solution {
    public int[] searchRange(int[] nums, int target) {
        int left=searchLeft(nums, target);
        int right=searchRight(nums, target);
        return new int[]{left,right};
    }
    public int searchLeft(int[] nums, int target){
        int left=0;
        int right=nums.length-1;
        while(left<=right){
            int mid=left+(right-left)/2;//防止内存溢出
            if(nums[mid]==target){
                if(mid==0 || nums[mid-1]!=target){
                    return mid;
                }
                right = mid-1;
            }else if(nums[mid]>target){
                right = mid -1;
            }else{
                left = mid +1;
            }
        }
        return -1;
    }
    public int searchRight(int[] nums, int target){
        int left=0;
        int right=nums.length-1;
        while(left<=right){
            int mid=left+(right-left)/2;//防止内存溢出
            if(nums[mid]==target){
                if(mid==nums.length-1 || nums[mid+1]!=target){
                    return mid;
                }
                left = mid+1;
            }else if(nums[mid]>target){
                right = mid -1;
            }else{
                left = mid +1;
            }
        }
        return -1;
    }
}
---------------------------------------------------
class Solution {
    public int[] searchRange(int[] nums, int target) {
        int leftOrder=searchLeft(nums, target);
        int rightOrder=searchRight(nums, target);
        if(leftOrder==-2 || rightOrder==-2) return new int[]{-1,-1};
		if(rightOrder-leftOrder>1) return new int[]{leftOrder+1,rightOrder-1};
		return new int[]{-1,-1};
    }
    public int searchLeft(int[] nums, int target){
        int left=0;
        int right=nums.length-1;
        int temp = -2;
        while(left<=right){
            int mid=left+(right-left)/2;//防止内存溢出
            if(nums[mid]>=target){
                right = mid -1;
                temp = right;
            }else{
                left = mid +1;
            }
        }
        return temp;
    }
    public int searchRight(int[] nums, int target){
        int left=0;
        int right=nums.length-1;
        int temp = -2;
        while(left<=right){
            int mid=left+(right-left)/2;//防止内存溢出
            if(nums[mid]>target){
                right = mid-1;
            }else{
                left = mid +1;
                temp = left;
            }
        }
        return temp;
    }
}

4. x的平方根 [69]

  • 袖珍计算器算法
    在这里插入图片描述
利用指数函数与对数函数代替平方根函数
时间复杂度:O(1)
--------------------------------
class Solution {
    public int mySqrt(int x) {
        int result = (int) Math.exp(0.5*Math.log(x));
        //注意判断result+1的平方是否定于x
        return (result+1)*(result+1) == x? result+1:result;
    }
}
  • 二分法
问题转换:根ans满足k^2<=x,所以对k进行二分查找[0,x],每一步比较mid*mid与x的值
时间复杂度:O(logx)
-----------------------------------------
class Solution {
    public int mySqrt(int x) {
        int left = 0,right = x,result=-1;
        while(left<=right){
            int mid = left+(right-left)/2;
            //注意类型转换,防止精度丢失
            if((long)mid*mid<=x){
                result=mid;
                left=mid+1;
            }else{
                right=mid-1;
            }
        }
        return result;
    }
}
  • 牛顿迭代
    请添加图片描述
class Solution {
    public int mySqrt(int x) {
        if(x==0) return 0;
        double x0 = x;

        while(true){
            //求出通项公式
            double result = 0.5*(x0+x/x0);
            if(Math.abs(x0 - result) < 1e-7){
            	return (int)result;
            }
            x0=result;
        }
    }
}

5.有效的完全平方数[367]

class Solution {
    public boolean isPerfectSquare(int num) {
        //不要 使用任何内置的库函数 --> 袖珍计算器法排除
        int left = 0;
        int right = num;
        int result = -1;
        while(left<=right){
            int mid = left+(right-left)/2;
            if((long)mid*mid<=num){
                result = mid;
                left = mid +1;
            }else{
                right = mid -1;
            }
        }
        return result*result==num?true:false;
    }
}

移除元素

1.移除元素[27]

  • 无名
可能是二分法做太多的原因,做啥都像二分法
-------------------------------------------------
class Solution {
    public int removeElement(int[] nums, int val) {
        //1.排序
        Arrays.sort(nums);
        
        //2.找左右边界
        int leftOrder = searchLeftOrder(nums,val);
        int rightOrder = searchRightOrder(nums,val);
        
        //3.边界值判断
        if(leftOrder==-2 || rightOrder==-2) return nums.length;
        
        //4.拼接新数组
        int vals = rightOrder-leftOrder-1;
        if(rightOrder!=nums.length){
        	for(int i=rightOrder;i<nums.length;i++){
        		nums[++leftOrder]=nums[i];
        	}
        }
        return nums.length-vals;
    }

    //找左边界
    public static int searchLeftOrder(int[] nums,int val){
        int left = 0;
        int right = nums.length-1;
        int leftOrder = -2;
        while(left<=right){
            int mid = left+(right-left)/2;
            if(nums[mid]>=val){
                right = mid-1;
                leftOrder=right;
            }else{
                left = mid+1;
            }
        }
        return leftOrder;
    }
    //找右边界
    public static int searchRightOrder(int[] nums,int val){
        int left = 0;
        int right = nums.length-1;
        int rightOrder = -2;
        while(left<=right){
            int mid = left+(right-left)/2;
            if(nums[mid]>val){
                right = mid-1;
            }else{
                left = mid+1;
                rightOrder=left;
            }
        }
        return rightOrder;
    }
}
  • 快慢双指针
class Solution {
    public int removeElement(int[] nums, int val) {
        int left=0;
        for(int i=0;i<nums.length;i++){
            if(nums[i]!=val){
                nums[left]=nums[i];
                left++;
            }
        }
        return left;
    }
}
  • 首尾双指针
class Solution {
    public int removeElement(int[] nums, int val) {
        //指向首尾的双指针
        int left=0;
        int right = nums.length;
        while(left<right){
            if(nums[left]==val){
                nums[left] = nums[right-1];
                right--;
            }else{
                left++;
            }
        }
        return left;
    }
}

2.删除有序数组中的重复项[26]

  • 快慢双指针
class Solution {
    public int removeDuplicates(int[] nums) {
        //快慢指针-由于数组顺序不能改变,故不能使用首尾指针
        int left = 0;
        for(int i=1;i<nums.length;i++){
            if(nums[left]!=nums[i]){
                left++;
                nums[left]=nums[i];
            }
        }
        return left+1;
    }
}

3.移动零[283]

  • 快慢双指针
class Solution {
    public void moveZeroes(int[] nums) {
        //快慢指针,是0直接覆盖,到达length后将末尾值直接赋值为0
        int left=0;
        for(int i=0;i<nums.length;i++){
            if(nums[i]!=0){
                nums[left]=nums[i];
                left++;
            }
        }
        for(int i=left;i<nums.length;i++){
            nums[i]=0;
        }
    }
}

4.比较含退格的字符串[844]

  • 无名
class Solution {
    public boolean backspaceCompare(String s, String t) {
        if(s.equals(t)) return true;
        //返回退格完成过后的字符串
        String s1 = backspaceNew(s);
        String t1 = backspaceNew(t);
        return s1.equals(t1);
    }
    public static String backspaceNew(String str){
        int start=0;
        //借助StringBuffer,方便删除元素
        StringBuffer sb = new StringBuffer(str);
        while(start<sb.length()){
            int index = sb.indexOf("#",start);
            if(index==-1){
                break;
            }
            if(index==0){
            	sb.deleteCharAt(index);
            	start=index;
            	continue;
            }
            sb.delete(index-1,index+1);
            start=index-1;
        }
        return sb.toString();
    }
}
  • 双指针
class Solution {
    public boolean backspaceCompare(String s, String t) {
        int i = s.length() - 1, j = t.length() - 1;
        int skipS = 0, skipT = 0;

        while (i >= 0 || j >= 0) {
            while (i >= 0) {
                if (s.charAt(i) == '#') {
                    skipS++;
                    i--;
                } else if (skipS > 0) {
                    skipS--;
                    i--;
                } else {
                    break;
                }
            }
            while (j >= 0) {
                if (t.charAt(j) == '#') {
                    skipT++;
                    j--;
                } else if (skipT > 0) {
                    skipT--;
                    j--;
                } else {
                    break;
                }
            }
            if (i >= 0 && j >= 0) {
                if (s.charAt(i) != t.charAt(j)) {
                    return false;
                }
            } else {
                if (i >= 0 || j >= 0) {
                    return false;
                }
            }
            i--;
            j--;
        }
        return true;
    }
}

5.有序数组的平方[977]

  • Arrays.sort
class Solution {
    public int[] sortedSquares(int[] nums) {
        for(int i=0;i<nums.length;i++){
            nums[i] = nums[i]*nums[i];
        }
        Arrays.sort(nums);
        return nums;
    }
}
  • 双指针
class Solution {
    public int[] sortedSquares(int[] nums) {
        int left = 0;
        int rigth = nums.length-1;
        int[] numsNew = new int[nums.length];
        int index = nums.length-1;
        while(left<=rigth){
        	if(Math.abs(nums[left])<=Math.abs(nums[rigth])){
        		numsNew[index]=nums[rigth]*nums[rigth];
        		rigth--;
        	}else{
        		numsNew[index]=nums[left]*nums[left];
        		left++;
        	}
        	index--;
        }
        return numsNew;
    }
}

长度最小的子数组

1.长度最小的子数组[209]

  • 暴力解法
class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        //长度最小的 连续子数组-->注意数组元素要连续
        int min=nums.length*2;
        int sum=0;
        for(int i=0;i<nums.length;i++){
            for(int j=i;j<nums.length;j++){
            	sum+=nums[j];
                if(sum>=target){
                    min=Math.min(min,j-i+1);
                    break;
                }
            }
            sum=0;
        }
        return min==nums.length*2?0:min;
    }
}
  • 前缀和 + 二分查找
  • 滑动窗口(双指针)
class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        //长度最小的 连续子数组-->注意数组元素要连续
        int start=0,end=0;
        int min = nums.length*2;
        int sum = 0;
        while(end<nums.length){
        	sum += nums[end];
            while(sum>=target){
                min=Math.min(end-start+1,min);
                sum -= nums[start++];
            }
            end++;
        }
        return min==nums.length*2?0:min;
    }
}

2.水果成篮[904]

3.最小覆盖子串[76]

螺旋矩阵

1.螺旋矩阵 II[59]

  • 模拟旋转过程
    请添加图片描述
class Solution {
    public int[][] generateMatrix(int n) {
        //模拟法:模拟旋转过程
        int [][]matrix = new int[n][n];//保存旋转结果
        int l=0,r=n-1,t=0,b=n-1;//左右上下
        int num = 1;//初值
        while(num<=n*n){
            for(int i=l;i<=r;i++) matrix[t][i]=num++;
            t++;
            for(int i=t;i<=b;i++) matrix[i][r]=num++;
            r--;
            for(int i=r;i>=l;i--) matrix[b][i]=num++;
            b--;
            for(int i=b;i>=t;i--) matrix[i][l]=num++;
            l++;
        }
        return matrix;
    }
}

2.螺旋矩阵[54]

  • 模拟旋转过程
上一题的逆过程,但注意数组边界与循环退出时机
-------------------------------------------
class Solution {
    public List<Integer> spiralOrder(int[][] matrix) {
        List<Integer> list = new ArrayList<Integer>();
        int n = matrix.length;//行数
        int m = matrix[0].length;//列数
        int length = n*m;//元素总数
        int l=0,r=m,t=0,b=n;
        //注意数组越界问题与循环结束时机
        while(list.size()<length){
            for(int i=l;i<r;i++) list.add(matrix[t][i]);
            t++;
            if(t==b) break;
            for(int i=t;i<b;i++) list.add(matrix[i][r-1]);
            r--;
            if(r==l) break;
            for(int i=r-1;i>=l;i--) list.add(matrix[b-1][i]);
            b--;
            for(int i=b-1;i>=t;i--) list.add(matrix[i][l]);
            l++;
        }
        return list;
    }
}

3.顺时针打印矩阵[剑指29]

  • 模拟旋转过程
注意边界!!!!!
-------------------------------------------
class Solution {
    public int[] spiralOrder(int[][] matrix) {
        int n = matrix.length;//行数
        if(n==0){return new int[0];}
        int m = matrix[0].length;//列数
        int length = n*m;//元素总数
        int num=0;//记录元素总数
		int[] array = new int[length];
        int l=0,r=m,t=0,b=n;
        //注意数组越界问题与循环结束时机
        while(num<length){
            for(int i=l;i<r;i++) array[num++]=matrix[t][i];
            t++;
            if(t==b) break;
            for(int i=t;i<b;i++) array[num++]=matrix[i][r-1];
            r--;
            if(r==l) break;
            for(int i=r-1;i>=l;i--) array[num++]=matrix[b-1][i];
            b--;
            if(t==b) break;
            for(int i=b-1;i>=t;i--) array[num++]=matrix[i][l];
            l++;
            if(r==l) break;
        }
        return array;
    }
}

总结

1.二分法

2.双指针法

  • 通过快指针和慢指针在一个for循环下完成两个for循环的工作

3.滑动窗口

  • 相当于首尾双指针

4.模拟行为

  • 不涉及算法,考察对代码的掌控能力
举报

相关推荐

0 条评论