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

1.线性表基础

1.1 线性表

线性表:具有相同特征数据元素的一个有限序列,其中所含元素的个数称为线性表的长度,从不同的角度看,线性表可以有不同的分类,例如:

  • 从语言实现的角度:C++和Java

在这里插入图片描述

一体式结构:存储表信息的单元和元素存储区以连续的方式安排在一块存储区里,两部分数据的整体形成一个完整的顺序表对象。这种结构整体性强,易于管理。但由于数据元素存储区是表对象的一部分,顺序表创建后,元素存储区就固定了。

分离式结构:表的对象里只保存与表有关的信息(容量和元素个数),实际数据元素存放在另一个独立的元素存储区里,通过链接与基本表对象关联。Java和Python。

  • 从存储的角度

顺序型:便于查找

链表型:便于修改

  • 访问限制角度

栈和队列又被称为访问受限的线性表,插入和删除遭到了限制,只能在固定的位置进行,而Hash比较特殊,其内部真正存储数据一般是数组,但是访问是通过映射来实现的,因此大部分材料里并不将Hash归结到线性表中。
在这里插入图片描述

  • 从扩容的角度:
    采用分离式结构的顺序表,若将数据区更为存储空间更大的区域,则可以再不改变表对象的前提下对其数据存储去进行了扩充,所有是使用这个表的地方都不必修改。只要程序运行环境(计算机系统)还有空闲存储,这种表结构就不会因为满了而导致操作无法进行。人们把采用这种技术实现的顺序表称为动态顺序表,因为其容量可以在使用中动态变化。

扩容的两种策略:

  • 每次扩充增加固定数目存储位置,比如十个,这种策略可称为线性增长。特点:节省空间,但是扩充操作频繁,操作次数多。
  • 每次扩充容量加倍。但是会浪费时间

Java基本是扩容时加倍的方式。而Python官方实现中,list实现采用了如下的策略:在建立空表或者很小的表时,系统分配一块能容纳8个元素的存储区;在执行插入操作(insert or append)时,如果元素存储区满,就换一块4倍大的存储区。但如果此时表已经很大(50000),就改变策略,采用加一倍的方法。

1.2 数组

数组是线性表最基本的结构,特点是元素是一个紧密在一起的序列,相互之间不需要记录彼此的关系就能访问,例如月份、星座等。

数组用索引的数字标识每一项数组在数组中的位置,且在大多数编程语言中,索引是从0开始算起的。我们可以根据数组中的索引快速的访问元素。

数组需要注意的点:

  • 从0开始记录,length-1结束
  • 元素在内存中连续存储,且每个元素占用相同大小的内存
  • length的长度一般不等于size(元素个数)

1.3 数组存储元素特征

1.创建一个大小为10的数组,请问此时数组里面是什么?

不同语言处理不同,C语言中每个位置都是一个随机数。在Java中,默认初始化为0。python中可以指定,例如a=[1.2.3.4],就是数组里面有四个元素,而a=[0 for i in range(10)] 这样定义的数组就是10个0.

2.是否可以只初始化一部分位置?初始化的本质是什么?

可以。

初始化的本质就是覆盖已有的值,用你需要的值覆盖原来的0,因为数组本来是一些默认值,然后后替换了一些数。此时如果想知道有效元素的个数,必须在使用一个额外的变量,例如size来标记。

3.上面已经初始化的元素之间是否可以空着,就是间隔着填有效值?

绝对不可以!

要初始化,就必须从前向后连续空间初始化,不可以出现空缺的情况,这是违背数组原则的。你可以进行某种运算期间给部分位置赋值,一旦稳定了,就不可以再出现空位置情况。

4.如果需要的数据是中间某一段怎么办?

用两个变量来表示 [left,right] 该区间是有效的。

5.删除操作?

删除一个元素后,后续元素向前移动。

2.数组基本操作

2.1数组创建和初始化

int [] arr = new int [10];

for(int i=0;i<arr.length;i++)
  arr[i]=i;

int []nums = {2,4,5,6,8};//背诵该初始化方式

2.2 查找一个元素

public static int findByELement (int [] arr,int size,int key)
{
	for( int i=0;i<size;i++)
	{
		if(arr[i] == key)
			return i;
			}
			return -1;
			}

很多题目本质就是查找问题,数组是查找的最佳载体。很多复杂的算法都是为了提高查找效率的,例如二分查找、二叉树、红黑树、B+树、Hash和堆等等。另一方面很多算法问题本质上都是查找问题,例如滑动窗口问题、回溯问题、动态规划问题等等都是在寻找那个目标结果。

2.3 增加一个元素

能准确处理游标和边界等情况是数组算法题最基础重要的问题之一。所以务必自己亲手写一个。

代码:

public static  int addByElementSequence (int[] arr ,int size,int element)
    {
        if(size >= arr.length)
            return -1;
        
        int index = size;
        
        for(int i=0;i<size;i++)
        {
            if(element<arr[i])
                index=i;
                break;
        }
        
        for(int j=size;j>index;j--)
        {
            arr[j]=arr[j-1];
            
        }
        
        arr[index] = element;
        return index;
    }

代码:

public static int addByElementSequence2(int[] arr, int size, int element) {
        //判断是否能插入,如果size>length 则空间已满
        if (size >= arr.length)
            return -1;

        int index = 0;

        for (int j = size; j > 0; j--) {
            if (element >= arr[j - 1]) {
                arr[j] = element;
                index = j;
                return index;
            }
            arr[j] = arr[j - 1];
        }
        
        arr[index] = element;
        return index;

    }

2.4 删除一个元素

对于删除,不能一边从后移动一边查找,元素可能不存在。
先检查元素是否存在,然后再删除。

public int removeByElement(int[]arr,int size ,int key)
{
	int index=-1;
	for(int i=0 ;i < size ;i++)
	{
	 	if(arr[i] == key)
	 	{	
	  		index=i;
	 			break;
	 	}
	}
		if(index!=-1)
		{
		for(int i = index+1;i<size;i++)
		  arr[i-1] = arr[i];
		  size-=1;
		  }
		  
 return size;
 }

单调数组问题

单调性

问题关键在于,同时返回一个能考虑到递增和递减序列的结果。

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

    public boolean isSorted (int [] nums,boolean increasing)
    {
        for(int i=0;i<nums.length;i++)
        {
            if(increasing){
                if(nums[i+1]<nums[i])
                return false;
            }else{
                if(nums[i+1]>nums[i])
                return true;
            }
        }
        return true;
    }
}

当然,如果同时出现大于和小于就一定不是单调了

class Solution {
    public boolean isMonotonic(int[] nums) {
        int index1 = -1;
        int index2 = -1;
        for(int i=0;i<nums.length-1;i++)
        {
            if(nums[i]<nums[i+1])
            index1 = i;
           else if(nums[i]>nums[i+1])
            index2=i;
        }
        if(index1==-1||index2==-1)
        return true;
        else 
        return false;
    }
}

单调性应用

在这里插入图片描述

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;
    }
}
public int searchInsert(int[]nums,int target){
	int n = nums.length;
	int left = 0,right=n-1,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;
	 }

数组合并问题

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

~Yogi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值