数组刷题 704.二分查找| 27. 移除元素 | 35. 搜索插入位置 |34. 在排序数组中查找元素的第一个和最后一个位置

数组

数组理论

数组是内存上的一个连续的空间,地址是连续的,用于存储数据。

int[][] array = new [2][3];

声明并初始化一个二维数组,代表是一个2行3列的二维数组。

Collections中的ArrayList 底层也是一个可变的Object数组

数组

####数组内置方法

在Java中,数组是基本的数据结构之一,提供了一些内置的方法来操作数组元素。以下是一些常用的数组方法:

  1. 长度获取
    • length:这是数组的一个属性,用于获取数组的长度,即数组中元素的数量。
  2. 元素克隆
    • clone():返回数组的一个副本。
  3. 排序
    • sort():数组元素的排序方法。对于整数数组,可以直接使用 sort() 方法进行排序。
  4. 二分查找
    • binarySearch(Object a, Object key):在给定的数组 a 中使用二分查找算法搜索 key。注意,数组必须先排序。
  5. 填充
    • fill(int a, int b, int val):从索引 a 到索引 b 填充数组元素 val
  6. 复制
    • copyOf(int[] original, int newLength):返回数组的副本,长度为 newLength
    • copyOfRange(int[] original, int from, int to):从原始数组中复制从 fromto(不包括 to)的元素到新数组。
  7. 比较
    • equals(Object anArray):比较两个数组是否相等。
  8. 查找特定元素
    • indexOf(int a, int val):返回数组中第一次出现的 val 的索引。
    • lastIndexOf(int a, int val):返回数组中最后一次出现的 val 的索引。
  9. 数组转换
    • toString():返回数组内容的字符串表示。
  10. 多维数组元素获取和设置
    • 对于多维数组,可以通过索引多次调用 getset 方法来获取和设置特定位置的元素。
数组静态方法

在Java中,java.util.Arrays 类提供了一组静态方法来操作数组。以下是一些常用的 java.util.Arrays 静态方法:

  1. 排序
    • sort(Object[] a):对对象数组进行升序排序。
    • sort(int[] a):对整型数组进行升序排序。
    • sort(long[] a):对长整型数组进行升序排序。
    • sort(short[] a):对短整型数组进行升序排序。
    • sort(char[] a):对字符数组进行升序排序。
    • sort(byte[] a):对字节数组进行升序排序。
    • sort(float[] a):对浮点型数组进行升序排序。
    • sort(double[] a):对双精度浮点型数组进行升序排序。
    • sort(Object[] a, Comparator c):使用自定义比较器对对象数组进行排序。
  2. 二分查找
    • binarySearch(Object[] a, Object key):在已排序的对象数组中进行二分查找。
  3. 填充
    • fill(Object[] a, Object val):用指定值填充数组。
    • fill(int[] a, int val):用指定整数值填充整型数组。
  4. 复制
    • copyOf(Object[] original, int newLength):创建一个新的数组,包含原数组的一部分或全部元素。
    • copyOfRange(Object[] original, int from, int to):创建一个新的数组,包含原数组从 fromto - 1 的元素。
  5. 比较
    • equals(Object[] a, Object[] a2):比较两个数组是否相等。
  6. 查找元素
    • indexOf(Object[] a, Object aElement):返回指定元素在数组中第一次出现的索引。
    • lastIndexOf(Object[] a, Object aElement):返回指定元素在数组中最后一次出现的索引。
  7. 数组转置
    • transpose(double[][] a):转置二维数组。
  8. 深度相等
    • deepEquals(Object[] a, Object a2):比较两个对象数组是否深度相等。
  9. 设置/获取数组元素
    • setAll(int[] array, IntUnaryOperator generator):为整型数组的每个元素设置新值。
    • setAll(Object[] array, IntFunction generator):为对象数组的每个元素设置新值。
  10. 并行排序
    • parallelSort(Object[] a):使用并行排序对对象数组进行排序。
  11. 流操作
    • stream(Object[] array):为对象数组创建一个流。
  12. 散布
    • setAll(Object[] array, IntFunction generator):为数组的每个位置设置一个值,该值由提供的函数生成。
  13. 数组深拷贝
    • deepCopyOf(Object[] original):创建对象数组的深拷贝。

ArrayList

ArrayList的扩容机制: 在声明时并不赋给他空间,在插入第一个元素时,容量扩展到10,每次扩容增大到之前的1.5倍左右

int newCapacity = oldCapacity + (oldCapacity >> 1);

####ArrayList常用方法:

ArrayList<Integer> array = new ArrayList<>();

ArrayList 是 Java 中的一个灵活且功能丰富的集合类,提供了许多用于操作列表的方法。以下是一些常用的 ArrayList 方法:

  1. 添加元素
    • add(E e): 在列表末尾添加一个元素。
    • add(int index, E element): 在指定位置插入一个元素。
  2. 获取元素
    • get(int index): 返回指定位置的元素。
  3. 修改元素
    • set(int index, E element): 用指定元素替换列表中指定位置的元素。
  4. 删除元素
    • remove(int index): 删除指定位置的元素,并返回被删除的元素。
    • remove(Object o): 删除列表中第一次出现的指定元素。
  5. 列表大小
    • size(): 返回列表中的元素数量。
  6. 容量管理
    • trimToSize(): 将列表的容量调整为列表的当前大小。
    • ensureCapacity(int minCapacity): 如有必要,增加列表的容量以至少满足最小容量。
  7. 空检查
    • isEmpty(): 如果列表为空,则返回 true
  8. 最大和最小值
    • max(): 返回列表中的最大元素。
    • min(): 返回列表中的最小元素。
  9. 列表遍历
    • 使用 for-each 循环或 Iterator 来遍历列表。
  10. 排序
    • sort(Comparator<? super E> c): 根据指定的比较器对列表进行排序。
  11. 子列表操作
    • subList(int fromIndex, int toIndex): 返回从 fromIndex(包括)到 toIndex(不包括)的列表视图。
  12. 清空列表
    • clear(): 移除列表中的所有元素。
  13. 克隆
    • clone(): 返回列表的一个副本。
  14. 查找元素
    • indexOf(Object o): 返回列表中第一次出现的指定元素的索引。
    • lastIndexOf(Object o): 返回列表中最后一次出现的指定元素的索引。
  15. 集合操作
    • contains(Object o): 如果列表包含指定元素,则返回 true
  16. 转换为数组
    • toArray(): 将列表转换为数组。
    • toArray(T[] a): 将列表转换为指定类型的数组。

704.二分查找

二分查找法,把已经排序好的数组 每次都从中间分开,if target > mid 就移动left , if target < mid ,then move right (按照升序排序)

值得注意的是 左闭右闭 还是 左闭右开 还有对 循环条件的判断

左闭右闭

left = 0,right = nums.length-1 , while(left <= right)

class Solution {
    public int search(int[] nums, int target) {
        int left = 0,right=nums.length-1;
        while(left <= right){
            int mid = (left + right) >> 1;
            if(target > nums[mid]){
                left = mid + 1;
            }else if(target < nums[mid]){
                right = mid - 1;
            }else{
                return mid;
            }
        }
        return -1;
    }
}

####左闭右开

left = 0 , right = nums.length , while(left < right)

class Solution {
    public int search(int[] nums, int target) {
        int left = 0,right=nums.length;
        while(left < right){
            int mid = (left + right) >> 1;
            if(target > nums[mid]){
                left = mid + 1;
            }else if(target < nums[mid]){
                right = mid;
            }else{
                return mid;
            }
        }
        return -1;
    }
}

27. 移除元素

数组在声明大小之后不可变,无法删除,只能覆盖

暴力解法

时间超限

class Solution {
    public int removeElement(int[] nums, int val) {

        int size = nums.length;
        for(int i = 0; i < nums.length; i++){
            if(nums[i] == val){//发现有相同的,集体前移
                for(int j = i+1;j < nums.length;j++ ){
                    nums[j-1] = nums[j];
                }
            }
            i--;//向前移动1位,需要重新检查该位
            size --;//长短 -1
        }
        return size;
    }
}
双指针

快慢指针

双指针法(快慢指针法): 通过一个快指针和慢指针在一个for循环下完成两个for循环的工作。

定义快慢指针

  • 快指针:寻找新数组的元素 ,新数组就是不含有目标元素的数组
  • 慢指针:指向更新 新数组下标的位置
class Solution {
    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;
    }
}

35. 搜索插入位置

左闭右闭
class Solution {
    public int searchInsert(int[] nums, int target) {
        int left = 0, right = nums.length - 1;

        while(left <= right){
            int 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 ? 0 : left;//如果找不到,此时 left > right; 
    }
}

####左闭右开

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

        while(left < right){//二分查找,如果能找到的话
            int mid = (left + right) >> 1;
            if(target > nums[mid]){
                left = mid + 1;
            }else if(target < nums[mid]){
                right = mid;
            }else{
                return mid;
            }
        }
        return right==0 ? 0 : right;//如果找不到,且此时 left=right=0,此时只能在0插入;否则直接在right插入因为right是开区间
    }
}

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

二分查找:可以扫描两次 分别确定 左边界和右边界

先找到情况条件:

1.target 不在 数组范围中 返回{-1,-1}
2.target 在数组范围中,但不在数组元素中,返回{-1,-1}
3.target 在数组范围且在元素中

第一次写法:

class Solution {

    public int[] searchRange(int[] nums, int target) {

        int left = 0,right = nums.length -1 ;

        //扫描右边界
        int rightBorder = -2;
        while(left <= right){
            int mid = (left + right) >> 1;
            if(target < nums[mid]){
                right = mid - 1;
            }else{
                left = mid + 1;
                rightBorder = mid;
            }
        }
        //扫描左边界
        int leftBorder = -2;
        left = 0;
        right = nums.length -1 ;
        while(left <= right){
            int mid = (left + right) >> 1;
            if(target > nums[mid]){
                left = mid + 1;
            }else{
                right = mid - 1;
                leftBorder = mid;
            }
        }
        //如果扫描后 不为target 返回{-1,-1}
        if(rightBorder < leftBorder) return new int[] {-1,-1};
        if (leftBorder == -2 || rightBorder == -2) return new int[] {-1, -1};
        else return new int[] {leftBorder,rightBorder};
    }
}

第二次写法

class Solution {

    int findRightBorder(int[] nums, int target){
        int rightBorder = -1;
        int left = 0,right = nums.length -1;
         while(left <= right){
            int mid = (left + right) >> 1;
            if(target < nums[mid]){
                right = mid - 1;
            }else{
                left = mid + 1;
                rightBorder = mid;
            }
        }
        return rightBorder;
    }

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

        while(left <= right){
            int mid = (left + right) >> 1;
            if(target > nums[mid]){
                left = mid + 1;
            }else{
                right = mid - 1;
                leftBorder = mid;
            }
        }
        return leftBorder;
    }

    public int[] searchRange(int[] nums, int target) {
        
        int rightBorder = findRightBorder(nums,target);
        int leftBorder = findLeftBorder(nums,target);

        if(leftBorder > rightBorder) return new int[] {-1,-1};
        else if (leftBorder == -1 || rightBorder == -1) return new int[] {-1, -1};
        else return new int[] {leftBorder,rightBorder};
        
    }
}
  • 27
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值