数组的进一步认识

本文介绍了Java数组的基本概念,如不可删除的特性及其内存管理。随后探讨了二分查找、搜索插入位置、查找元素边界、平方根计算、完全平方数判断、移除重复元素和数组操作优化等算法。通过实例演示了如何高效解决实际问题,如排序数组操作和算法复杂度控制。
摘要由CSDN通过智能技术生成

数组

1、数组的认识

​ 1.加一步了解了数组,在Java中,数组不能删除,所谓的删除只是有一个封装好的方法覆盖。同时,在操作数组的时候,我们对当前产生的数组的地址无法删除,只能覆盖,例如:假设int[] a = new int [5]; 在这个代码中,你已经产生了了五个地址,但是你世纪用到的只有三个或者四个,打印出来的地址也是三四个,但是在计算机内存中,产生的依旧是五个地址,对此要理解到位

2、二分法的使用

704. 二分查找

难度简单1021收藏分享切换为英文接收动态反馈

给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1

示例 1:

输入: nums = [-1,0,3,5,9,12], target = 9
输出: 4
解释: 9 出现在 nums 中并且下标为 4

示例 2:

输入: nums = [-1,0,3,5,9,12], target = 2
输出: -1
解释: 2 不存在 nums 中因此返回 -1

解法:在二分法中,我们必须清除的知道界限的使用,对于本题,我们有两种解法,

其一:

public int search(int[] nums, int target) {
       int left = 0;
       int right = nums.length;

       while(left < right){
           int mid = left + ((right - left)/2);
           if(nums[mid] > target){
                right = mid;
           }else if(nums[mid] < target){
                left = mid + 1;
           }else if(nums[mid] == target){
               return mid;
           }
       }
       return -1;
    }
    
    //这是通过定义一个左闭右开的区间进行解题,也是较为优解的,通过不断比较中间值,来重新定义左右边界值,然后遍历,找到我们所需要的值

解法二:

public int search(int[] nums, int target) {
       int left = 0;
       int right = nums.length -1;

       while(left <= right){
           int mid = left + ((right - left) >> 1);
           if(nums[mid] > target){
                right = mid - 1;
           }else if(nums[mid] < target){
                left = mid + 1;
           }else if(nums[mid] == target){
               return mid;
           }
       }
       return -1;
    }
//这是一个左闭右必的区间,我们要清除定义对所取区间的范围,然后才能针对解题

35. 搜索插入位置

难度简单1753收藏分享切换为英文接收动态反馈

给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。

请必须使用时间复杂度为 O(log n) 的算法。

示例 1:

输入: nums = [1,3,5,6], target = 5
输出: 2

示例 2:

输入: nums = [1,3,5,6], target = 2
输出: 1

示例 3:

输入: nums = [1,3,5,6], target = 7
输出: 4
public int search(int[] nums, int target) {
       int left = 0;
       int right = nums.length;

       while(left < right){
           int mid = left + ((right - left)/2);
           if(nums[mid] > target){
                right = mid;
           }else if(nums[mid] < target){
                left = mid + 1;
           }else if(nums[mid] == target){
               return mid;
           }
       }
       return -1;
    }
//本题中,我们要自己构造出一个区间,然后进行遍历,找到答案

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

难度中等1963收藏分享切换为英文接收动态反馈

给你一个按照非递减顺序排列的整数数组 nums,和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。

如果数组中不存在目标值 target,返回 [-1, -1]

你必须设计并实现时间复杂度为 O(log n) 的算法解决此问题。

示例 1:

输入:nums = [5,7,7,8,8,10], target = 8
输出:[3,4]

示例 2:

输入:nums = [5,7,7,8,8,10], target = 6
输出:[-1,-1]

示例 3:

输入:nums = [], target = 0
输出:[-1,-1]
public int[] searchRange(int[] nums, int target) {
        int index = binarySeach(nums,target);
        if(index==-1){
            return new int[]{-1,-1};
        }
        int left =index;
        int right = index;
        while(left-1>=0 && nums[left-1]==nums[index]){//向左滑动,找左边界
            left--;
        }
        while(right+1<nums.length && nums[right+1]==nums[index]){//向右滑动,找右边界
            right++;
        }
        return new int[]{left,right};
    }

    public int binarySeach(int[] nums, int target) {
        int left=0,right=nums.length;
        while(left<right){
            int mid=left+(right-left)/2;//找到一个中位数
            if(nums[mid]==target){
                return mid;
            }else if(nums[mid]>target){
                right=mid;
            }else if(nums[mid]<target){
                left=mid+1;
            }
        }
        return -1;
    }
//通过构造一个方法,用二分法找出它是否存在于数组中,如果存在,则继续通过滑动,分别向左右滑动找到我们所需要的边界,知道我们找到答案,则返回一个新的数组,不存在则返回[-1,-1],

69. x 的平方根

难度简单1172收藏分享切换为英文接收动态反馈

给你一个非负整数 x ,计算并返回 x算术平方根

由于返回类型是整数,结果只保留 整数部分 ,小数部分将被 舍去 。

**注意:**不允许使用任何内置指数函数和算符,例如 pow(x, 0.5) 或者 x ** 0.5

示例 1:

输入:x = 4
输出:2

示例 2:

输入:x = 8
输出:2
解释:8 的算术平方根是 2.82842..., 由于返回类型是整数,小数部分将被舍去。
public int mySqrt(int x) {
        int left =1;
        int ritht = x;
        int middle = 0;
        while( ritht >= left){
            middle = left + (ritht-left)/2;
            int temp = x / middle;
            if(temp > middle){
                left = middle +1;
            }else if(temp<middle){
                ritht = middle-1;
            }else if(temp == middle){
                return middle;
            }
        }
        return ritht;
    }

367. 有效的完全平方数

难度简单447收藏分享切换为英文接收动态反馈

给定一个 正整数 num ,编写一个函数,如果 num 是一个完全平方数,则返回 true ,否则返回 false

进阶:不要 使用任何内置的库函数,如 sqrt

示例 1:

输入:num = 16
输出:true

示例 2:

输入:num = 14
输出:false
 public boolean isPerfectSquare(int num) {
        int left = 1;
        int rigtht = num;
        while( left <= rigtht){
            int middle = left + (rigtht - left) / 2;
            int temp = num/middle;
            if( temp == middle){
                
                if(num % middle ==0){//必须判定一些特例
                    return true;
                }
               left = middle+1;//左右边界都行
            }else if( middle > temp){
                rigtht = middle -1;
            }else if( middle < temp){
                left = middle + 1;
            }
        }
        return false;
    }

3、移除元素

27. 移除元素

难度简单1537收藏分享切换为英文接收动态反馈

给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。

不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组

元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。

说明:

为什么返回数值是整数,但输出的答案是数组呢?

请注意,输入数组是以**「引用」**方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。

你可以想象内部操作如下:

// nums 是以“引用”方式传递的。也就是说,不对实参作任何拷贝
int len = removeElement(nums, val);

// 在函数里修改输入数组对于调用者是可见的。
// 根据你的函数返回的长度, 它会打印出数组中 该长度范围内 的所有元素。
for (int i = 0; i < len; i++) {
    print(nums[i]);
}

示例 1:

输入:nums = [3,2,2,3], val = 3
输出:2, nums = [2,2]
解释:函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。你不需要考虑数组中超出新长度后面的元素。例如,函数返回的新长度为 2 ,而 nums = [2,2,3,3] 或 nums = [2,2,0,0],也会被视作正确答案。

示例 2:

输入:nums = [0,1,2,2,3,0,4,2], val = 2
输出:5, nums = [0,1,4,0,3]
解释:函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。注意这五个元素可为任意顺序。你不需要考虑数组中超出新长度后面的元素。
 public int removeElement(int[] nums, int val) {
      int leftIndex=0;
      int rightIndex=nums.length-1;
      while(rightIndex >= 0 && nums[rightIndex]==val) rightIndex--;//滑动到一个不等于var值的位置
      while(leftIndex<=rightIndex){
          if(nums[leftIndex]==val){
              nums[leftIndex]=nums[rightIndex];
              rightIndex--;
          }
          leftIndex++;
         while(rightIndex >= 0 && nums[rightIndex]==val) rightIndex--;//更新数组
      }
      return leftIndex;
    }
//双指针法:将右边指针的的值覆盖掉左边指针的值,当遇到等于var值的情况,需要向前滑动一位,达成覆盖的效果
public int removeElement(int[] nums, int val) {
        int slowIndex = 0;
        for (int fastIndex = 0; fastIndex < nums.length; fastIndex++) {
            if (nums[fastIndex] != val) {
                nums[slowIndex] = nums[fastIndex];
                slowIndex++;
            }
        }
        return slowIndex;
    }
// 快慢指针

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

难度简单2890收藏分享切换为英文接收动态反馈

给你一个 升序排列 的数组 nums ,请你** 原地** 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致

由于在某些语言中不能改变数组的长度,所以必须将结果放在数组nums的第一部分。更规范地说,如果在删除重复项之后有 k 个元素,那么 nums 的前 k 个元素应该保存最终结果。

将最终结果插入 nums 的前 k 个位置后返回 k

不要使用额外的空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。

判题标准:

系统会用下面的代码来测试你的题解:

int[] nums = [...]; // 输入数组
int[] expectedNums = [...]; // 长度正确的期望答案

int k = removeDuplicates(nums); // 调用

assert k == expectedNums.length;
for (int i = 0; i < k; i++) {
    assert nums[i] == expectedNums[i];
}

如果所有断言都通过,那么您的题解将被 通过

示例 1:

输入:nums = [1,1,2]
输出:2, nums = [1,2,_]
解释:函数应该返回新的长度 2 ,并且原数组 nums 的前两个元素被修改为 1, 2 。不需要考虑数组中超出新长度后面的元素。

示例 2:

输入:nums = [0,0,1,1,1,2,2,3,3,4]
输出:5, nums = [0,1,2,3,4]
解释:函数应该返回新的长度 5 , 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4 。不需要考虑数组中超出新长度后面的元素。
public int removeDuplicates(int[] nums) {
       int left = 0;
       int right = 1;

       while(right < nums.length){

           if(nums[left] == nums[right]){
               right++;
           }else{
               left++;
               nums[left] = nums[right];
               right++;
           }
       }
       return left+1;
    }

283. 移动零

难度简单1769收藏分享切换为英文接收动态反馈

给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。

请注意 ,必须在不复制数组的情况下原地对数组进行操作。

示例 1:

输入: nums = [0,1,0,3,12]
输出: [1,3,12,0,0]

示例 2:

输入: nums = [0]
输出: [0]
 public void moveZeroes(int[] nums) {
        int left = 0;
        for(int right = 0;right<nums.length;right++){
            if(nums[right] != 0){
                nums[left] = nums[right];
                left++;
            }
        } 
        for(int right =left; right<nums.length ;right++){
            nums[right] =0;
        }
    }

4、有序数组的平方

977. 有序数组的平方

难度简单648收藏分享切换为英文接收动态反馈

给你一个按 非递减顺序 排序的整数数组 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]
public int[] sortedSquares(int[] nums) {
       int left=0;
       int right=nums.length-1;
       int[] resule = new int[nums.length];
       int index = resule.length-1;
       while(left<=right){
           if(nums[left]*nums[left]<nums[right]*nums[right]){
               resule[index--]=nums[right]*nums[right--];
           }else{
               resule[index--]=nums[left]*nums[left++];
           }
       }
       return resule;
    }
//双指针法:

5、长度最小的子数组

209. 长度最小的子数组

难度中等1420收藏分享切换为英文接收动态反馈

给定一个含有 n 个正整数的数组和一个正整数 target

找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度**。**如果不存在符合条件的子数组,返回 0

示例 1:

输入:target = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3] 是该条件下的长度最小的子数组。

示例 2:

输入:target = 4, nums = [1,4,4]
输出:1

示例 3:

输入:target = 11, nums = [1,1,1,1,1,1,1,1]
输出:0
public int minSubArrayLen(int target, int[] nums) {
       int temp=0;
       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){
               int res = right-left+1;
               sum -= nums[left];
               left++;
               result = result > res ? res : result;
           }
       }
       return result == Integer.MAX_VALUE ? 0 :result;
    }
//通过滑动窗口,即通过一个窗口,比较窗口内的值是否等于我们所需要的值,然后进行滑动

904. 水果成篮

难度中等372收藏分享切换为英文接收动态反馈

你正在探访一家农场,农场从左到右种植了一排果树。这些树用一个整数数组 fruits 表示,其中 fruits[i] 是第 i 棵树上的水果 种类

你想要尽可能多地收集水果。然而,农场的主人设定了一些严格的规矩,你必须按照要求采摘水果:

  • 你只有 两个 篮子,并且每个篮子只能装 单一类型 的水果。每个篮子能够装的水果总量没有限制。
  • 你可以选择任意一棵树开始采摘,你必须从 每棵 树(包括开始采摘的树)上 恰好摘一个水果 。采摘的水果应当符合篮子中的水果类型。每采摘一次,你将会向右移动到下一棵树,并继续采摘。
  • 一旦你走到某棵树前,但水果不符合篮子的水果类型,那么就必须停止采摘。

给你一个整数数组 fruits ,返回你可以收集的水果的 最大 数目。

示例 1:

输入:fruits = [1,2,1]
输出:3
解释:可以采摘全部 3 棵树。

示例 2:

输入:fruits = [0,1,2,2]
输出:3
解释:可以采摘 [1,2,2] 这三棵树。
如果从第一棵树开始采摘,则只能采摘 [0,1] 这两棵树。

示例 3:

输入:fruits = [1,2,3,2,2]
输出:4
解释:可以采摘 [2,3,2,2] 这四棵树。
如果从第一棵树开始采摘,则只能采摘 [1,2] 这两棵树。

示例 4:

输入:fruits = [3,3,3,1,2,1,1,2,3,3,4]
输出:5
解释:可以采摘 [1,2,1,1,2] 这五棵树。
public int totalFruit(int[] fruits) {
        int left = 0;
        int ans = 0;//开始为0
        int maxLen = 0;
        int[] count = new int[fruits.length];
        for(int right = 0; right<fruits.length; right++ ){
            if(count[fruits[right]]==0){
                ans++;
            }
            count[fruits[right]]++;
            while(ans>2){
                count[fruits[left]]--;
                if(count[fruits[left]]==0){
                    ans--;
                }
                left++;
            }
            maxLen = Math.max(maxLen,right-left+1);
        }
        return maxLen;
    }
//同样也是用滑动窗口的方法进行处理,在窗口中出现ans>2的情况下,进行处理

6、螺旋矩阵

59. 螺旋矩阵 II

难度中等848收藏分享切换为英文接收动态反馈

给你一个正整数 n ,生成一个包含 1n2 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix

示例 1:

img

输入:n = 3
输出:[[1,2,3],[8,9,4],[7,6,5]]

示例 2:

输入:n = 1
输出:[[1]]
public int[][] generateMatrix(int n) {
        int[][] res = new int[n][n];
        int i,j;
        int start = 0;
        int count = 1;
        int loop = 0;//控制循环次数

        while(loop++ < n/2){
            //上面从左往右
            for(j=start;j<n-loop;j++){
                res[start][j] = count++;
            }

            //右边从上往下
            for(i=start;i<n-loop;i++){
                res[i][j] = count++;
            }

            //下面从右往左
            for(;j>=loop;j--){
                res[i][j] = count++;
            }


            //左边从下往上
            for(; i>=loop ; i--){
                res[i][j] = count++;
            }
            start++;
        }

        //如果为奇数,为中间赋值
        if(n % 2 == 1){
            res[start][start] = count;
        }

        return res;
    }

//分别处理数据的四个方向上的数据,并对中间的数据进心处理,但于此同时,但记得控制好边界范围

54. 螺旋矩阵

难度中等1240收藏分享切换为英文接收动态反馈

给你一个 mn 列的矩阵 matrix ,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。

示例 1:

img

输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
输出:[1,2,3,6,9,8,7,4,5]

示例 2:

img

输入:matrix = [[1,2,3,4],[5,6,7,8],[9,10,11,12]]
输出:[1,2,3,4,8,12,11,10,9,5,6,7]
 public List<Integer> spiralOrder(int[][] matrix) {
        if(matrix == null || matrix.length == 0|| matrix[0].length==0 ){
            return new LinkedList<>();
        }
        int m = matrix.length, n = matrix[0].length;
        int up = 0, down = m-1, left = 0, right = n-1;
        List<Integer> list = new LinkedList<>();
        while(left<=right && up<=down){
            //上面遍历
            for(int i = left;i<=right;i++){
                    list.add(matrix[up][i]);
            }
            up++;
            //右边遍历
            for(int i = up;i<=down;i++){
                    list.add(matrix[i][right]);
            }
            right--;
            //下面遍历
            for(int i = right;i >=left && down >= up;i--){
                list.add(matrix[down][i]);
            }
            down--;
            //左边遍历
            for(int i = down;i>=up && right >= left ;i--){
                list.add(matrix[i][left]);
            }
            left++;
        }
        return list;
    }

//利用链表,对数据进行处理,但是记得,在下面以及左边的遍历的时候,为了防止数组重新打印,必须加上第二层条件,佛则数据会重复打印
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值