算法通关村——不简单的数组增删改查

1. 有序数组添加元素

先找到要插入元素的位置,然后将这个位置包括之后的元素都后移一位,然后插入元素进入数组。首先需要判断当前数组能不能继续添加元素。

    /**
     * 插入指定位置元素
     *
     * @param arr     有序数组
     * @param size    已经存储的元素数量,从1开始
     * @param element 插入的元素
     * @return
     */
    public static int addByElement(int[] arr, int size, int element) {
    
    
        // size从1开始表示实际个数,arr.length也是从1开始
        if (size >= arr.length) {
    
    
            return -1;
        }
        // 防止插入的数大于当前最大值
        int index = size;
        for (int i = 0; i < size; i++) {
    
    
            if (element < arr[i]) {
    
    
                index = i;
                break;
            }
        }
        // j开始元素都后移
        for (int j = size; j > index; j--) {
    
    
            arr[j] = arr[j - 1];
        }
        // 插入元素
        arr[index] = element;
        return index;
    }

2. 删除指定位置元素

先找到删除元素所存在的位置,如果位置存在,记录下来,然后判断这个位置下标是不是-1.不是-1表示存在,然后将删除元素后面的元素都前移。

  /**
     * 删除元素key
     *
     * @param arr  数组
     * @param size 数组元素个数从1开始
     * @param key  删除元素
     * @return
     */
    public static int removeByElement(int[] arr, int size, int key) {
    
    
        if (size >= arr.length) {
    
    
            return -1;
        }
        // index是-1,表示不存在
        int index = -1;
        for (int i = 0; i < size; i++) {
    
    
            if (arr[i] == key) {
    
    
                index = key;
                break;
            }
        }
        if (index != -1) {
    
    
            for (int i = index + 1; i < size; i++) {
    
    
                arr[i - 1] = arr[i];
                size--;
            }
        }
        return size;
    }

3. 单调数列

单调数列
如果数组是单调递增或单调递减的,那么它是 单调 的。
如果对于所有 i <= j,nums[i] <= nums[j],那么数组 nums 是单调递增的。 如果对于所有 i <= j,nums[i]> = nums[j],那么数组 nums 是单调递减的。
当给定的数组 nums 是单调数组时返回 true,否则返回 false。

3.1 分析

由于题目里面是包含递增和递减的,直接判断无法知道是递增还是递减,所以需要使用两个变量inc,desc来记录,如果元素都是递增的,那么最后使用inc|| desc 只会是true,一旦是fasle就表明,不是单调的。

    public boolean isMonotonic(int[] nums) {
    
    
    	// 递增标志
        boolean inc = true;
        // 递减标志
        boolean desc = true;
        for(int i=0;i<nums.length-1;i++){
    
    
            if(nums[i]>nums[i+1]){
    
    
            // 由于是递减的,所以递增的不满足,设置为false
                inc = false;
            }
			// 同理
            if(nums[i] < nums[i+1]){
    
    
                desc = false;
            }
        }
		// 只要一个为true就是true,如果都是false那么就不是递增的
        return inc || desc;
    }

4. 搜索插入位置

搜索插入位置
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
请必须使用时间复杂度为 O(log n) 的算法。

4.1 分析

题目要求logn的时间复杂度,第一时间想到二分。

   public int searchInsert(int[] nums, int target) {
    
    
        int n = nums.length;
        int left =0;
        int right = n-1;
        int ans = n;
        while(left<=right){
    
    
        // 这里要加上相应的括号,否则优先级会报错
            int mid = ((right-left) >>1) +left;
            if(target<=nums[mid]){
    
    
                ans = mid;
                right = mid-1;
            }else{
    
    
                left = mid+1;
            }
        }
        return ans;
    }

5. 合并两个有序数组

合并两个有序数组
给你两个按非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目。
请你合并 nums2 到 nums1 中,使合并后的数组同样按 非递减顺序 排列。
注意:最终,合并后数组不应由函数返回,而是存储在数组 nums1 中。为了应对这种情况,nums1 的初始长度为 m + n,其中前 m 个元素表示应合并的元素,后 n 个元素为 0 ,应忽略。nums2 的长度为 n 。

5.1 分析

5.1.1 先将元素都添加到nums1里面去,然后对nums1排序。

 public void merge(int[] nums1, int m, int[] nums2, int n) {
    
    
      for(int i=0;i<nums2.length;i++){
    
    
          nums1[m+i] = nums2[i];
      }      
      Arrays.sort(nums1);
    }

在这里插入图片描述
但是很显然效率是不高的,第一此遍历nums2,时间复杂度是O(n), 第二次使用Arrays排序,底层是快排,时间复杂度是O(nlogn)

5.2.2 由于两个数组都是有序的,只需要比较两个数组的最后一个元素,将大的放入nums1的末尾,最后将未完成的元素放入nums1里面。

    public static void merge(int[] nums1, int m, int[] nums2, int n) {
    
    
        // 合并索引位置
        int i = m + n - 1;
        // nums1的最后一个元素
        int len1 = m - 1;
        // nums2的最后一个元素
        int len2 = n - 1;
        while (len1 >= 0 && len2 >= 0) {
    
    
            if (nums1[len1] <= nums2[len2]) {
    
    
                // 将最大的元素放入nums1的末尾
                nums1[i--] = nums2[len2--];
            } else {
    
    
                nums1[i--] = nums1[len1--];
            }
        }
        // 判断剩余数组是否有空余元素
        while (len2 != -1) nums1[i--] = nums2[len2--];
        while (len1 != -1) nums1[i--] = nums1[len1--];
    }

在这里插入图片描述
这里面的时间复杂度就是O(m+n)两个数组的长度。可以看出效率还是很高的、

总结

数组问题的难点在于如何选择相对合理的方式来解决问题,尤其是数组的增加元素,删除元素的这种移动尤其需要注意。

猜你喜欢

转载自blog.csdn.net/qq_52843958/article/details/131899516