青铜挑战——不简单的数组增删改查

1.线性表

所谓线性表就是具有相同特征数据元素的一个有限序列,其中所含元素的个数称为线性表的长度
从存储角度看
可以分为顺序型和链表型。顺序型就是将数据存放在一段固定的区间内,此时访问元素的效率非常高,但是删除和增加元素的代价比较大,如果要扩容只能整体搬迁。(数组)
链表型,是通过地址依次连接,因此访问时必须从头开始逐步向后找,查找效率低,而删除和增加元素非常方便,并且也不需要考虑扩容问题。
从访问限制角度看
栈和队列又称为受限制的线性表,插入和删除受到了限制,只能在固定位置进行
image.png

2.数组

数组是最基本的结构,特点是元素是一个紧密在一起的序列,相互之间不需要记录彼此的关系就能访问

1.数组的查找
 public static int find(int [] array, int key) {
        for (int i = 0; i < array.length; i++) {
            if (array[i] >= key) {
                return array[i];
            }
        }
        return -1;
    }
2.数组的增加

数组的插入,需要先找到需要插入的位置将后面的元素依次往后移最后再插入
注意点: index = size是为了解决没有找到插入位置直接插入到尾部。

/**
     * 有序数组的插入
     * @param array 数组
     * @param size 实际长度 从1开始
     * @param element 插入的元素
     * @return 插入的位置
     */
    public static int addByElementSequence(int [] array, int size, int element) {
        //实际长度大于等于数组大小不能插入
        if (size >= array.length) {
            return -1;
        }
        //必须为size应为如果遍历整个数组都找不到,比element大的就插入在数组最后
        int index = size;
        for (int i = 0; i < size; i++) {
            if (element < array[i]) {
                index = i;
                break;
            }
        }
        //将后面的元素往后移动
        //因为size从1开始index从0开始所以为j=size
        for (int j = size; j > index ; j--) {
            array[j] = array[j - 1];
        }
        array[index] = element;
        return index;
    }

还可以从后往前遍历,边查找边往后移,没有找到就往后移找到就直接插入

public static int addByElementSequence2(int [] array, int size, int element) {
        int index = 0;
        //实际长度大于等于数组大小不能插入
        if (size >= array.length) {
            return -1;
        }
        for (int i = size - 1; i > 0 ; i--) {
            if (element > array[i]) {
                index = i + 1;
                array[index] = element;
                break;
            }
            array[i + 1] = array[i];
        }
        return index;
    }
3.数组的删除元素

对于删除,不能一边从后向前移动一边查找,因为元素可能不存在。所有要先查找元素是否存在,再往前移动

public static int deleteByElement(int [] array, int size, int key) {
        //查找删除的位置
        int index = -1;
        for (int i = 0; i < size; i++) {
            if (array[i] == key) {
                index = i;
                break;
            }
        }
        //如果存在后面的元素依次往前移动,并且size--
        if (index != -1) {
            for (int i = index + 1; i < size; i++) {
                array[i - 1] = array[i];
            }
            size--;
        }
        return size;
    }

3.单调数组问题

896.单调数列
如果吞吐量是单调递增或单调递减的,那么它就是 单调
如果对于所有i <= j,nums[i] <= nums[j],那么集群nums是单调递增的。 如果对于所有i <= j,nums[i]> = nums[j],那么集群nums 是单调递减的。
当给定的负载nums 是单调负载时返回true,否则返回false。
示例1:
输入: nums = [1,2,2,3] 输出: true
示例2:
输入: nums = [6,5,4,4] 输出: true
示例3:
输入: nums = [1,3,2] 输出: false

解题思路:
如果数组单调则必然 nums[i] > nums[i+1] 单调递减,nums[i] < nums[i+1] 单调递增,所以只需要遍历数组判断是否单调,有两种情况所以需要遍历两次

public boolean isMonotonic(int[] nums) {
    return isSorted(nums,true) | isSorted(nums,false);
}

/**
 * 判断是否递增或者递减
 * @param nums 数组
 * @param increasing 是否递增
 * @return
 */
public boolean isSorted(int [] nums, boolean increasing) {
    int l = nums.length;
    for (int i = 0; i < l - 1; i++) {
        if (increasing) {
            if (nums[i] > nums[i + 1]) {
                return false;
            }
        } else {
            if (nums[i] < nums[i + 1]) {
                return false;
            }
        }
    }
    return true;
}

优化:
两次循环可以优化成一次,假如我们在i和i+1位置出现了nums[i]>nums[i+1],而在另外一个地方j和j+1出现了nums[j]<nums[j+1],那是不是说明就不是单调了呢?这样我们就可以使用两个变量标记一下就行了,代码如下:

 public static boolean isMonotonic2(int[] nums) {
        boolean inc = true, dec = true;
        int l = nums.length;
        for (int i = 0; i < l - 1; i++) {
            if (nums[i] > nums[i + 1]) {
                inc = false;
            }
            if (nums[i] < nums[i + 1]) {
                dec = false;
            }
        }
        return inc | dec;
    }

4.数组组合问题

88.合并两个有序数组
给你两个按 非递减顺序 排列的整数数组 nums1_ 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目。
请你 合并 nums2
_到 nums1 中,使合并后的数组同样按 非递减顺序 排列。
**注意:**最终,合并后数组不应由函数返回,而是存储在数组 nums1 中。为了应对这种情况,nums1 的初始长度为 m + n,其中前 m 个元素表示应合并的元素,后 n 个元素为 0 ,应忽略。nums2 的长度为 n 。
示例 1:
输入:nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3 输出:[1,2,2,3,5,6] 解释:需要合并 [1,2,3] 和 [2,5,6] 。 合并结果是 [1,2,2,3,5,6] ,其中斜体加粗标注的为 nums1 中的元素。
解题思路:
直接插入的话要不断的移动元素,所以可以从后往前插入,对比nums1 和nums2大的插入,当有一个长度为0的将剩余的直接插入’

 public static void merge(int[] nums1, int m, int[] nums2, int n) {
        int i = m + n - 1;
        int len1 = m - 1, len2 = n - 1;
        while (len1 >= 0 && len2 >= 0) {
            if (nums1[len1] >= nums2[len2]) {
                nums1[i--] = nums1[len1--];
            } else {
                nums1[i--] = nums2[len2--];
            }
        }
        while (len1 != -1) {
            nums1[i--] = nums1[len1--];
        }
        while (len2 != -1) {
            nums1[i--] = nums2[len2--];
        }
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值