六六力扣刷题数组之理论基础

简介: 六六力扣刷题数组之理论基础

前言

之前小六六一直觉得自己的算法比较菜,算是一个短板吧,以前刷题也还真是三天打鱼,两天晒网,刷几天,然后就慢慢的不坚持了,所以这次,借助平台的活动,打算慢慢的开始开刷,并且自己还会给刷的题总结下,谈谈自己的一些思考,和自己的思路等等,希望对小伙伴能有所帮助吧,也可以借此机会把自己短板补一补,希望自己能坚持下去呀

之前刷了不少题了,这边又开始了,这个月从数组刷起吧,嘿嘿,感谢掘金和大家的支持,我们冲

数组理论基础

数组是数据结构中最基础的结构,是很多高级数据结构实现的基石,打好这个基础才能走的更远。数组与链表是物理内存中真实存在的物理结构,二叉树、二叉搜索树、红黑树、图、堆等其他数据结构都是属于逻辑结构,底层都是用数组和链表实现。

数组是存放在连续内存空间上的相同类型数据的集合。可以方便的通过下标索引的方式获取到下标下对应的数据。

不能单独删除、释放数组中的某个元素,只能覆盖。如果要释放,就是全释放(程序运行结束,回收内存栈空间)。

因为数组的在内存空间的地址是连续的,所以我们在删除或者增添元素的时候,就难免要移动其他元素的地址。对于数组来说,在尾部插入、删除元素是比较高效的,时间复杂度是 O(1),但是如果在中间或者开头插入、删除元素,就会涉及数据的搬移,时间复杂度为 O(N),效率较低。

技巧: 把待删除元素交换到最后一个,然后再删除,就可以避免数据搬移。

使用双指针法,可原地修改数组

什么是数组

数组(Array):一种线性表数据结构,用一组连续的内存空间,来存储一组具有相同类型的数据。 通过数组的定义,我们可以看到数组是一种线性表数据结构。线性表,顾名思义,就是将存储的数据排成一条线一样的结构,存储的每个数据最多只有前后两个方向。

数组是用连续内存空间存储相同类型的元素,就是因为有这个限制条件,使得数组按照下标随机访问(随机访问:可以用同等的时间访问到一组数据中的任意一个元素)数组中数据元素时间复杂度达到 O(1) 级别。当然这样的限制也有缺点,在头部或者中间进行数据删除、插入操作时,为了保证这个连续性,需要对数据进行大量的复制迁移来保持此特性。

下面我们通过代码来看一下,数组是如何通过下标来访问数据,使得时间复杂度达到 O(1) 级别的。

// 数组初始化必须为它指定初始容量
int[] i = new int[10];

上面的代码,我们声明了一个数组 i ,i 是这个数组的引用变量,指向这个数组的首地址(计算机会给每个内存单元分配一个地址,计算机通过这个地址来访问内存中的数据)。因为数组是连续的内存空间且数据类型相同,当我们知道了数据的首地址,便可以通过下面的公式,计算出数组中每个元素的内存地址,然后让计算机直接访问,达到 O(1) 级别的时间复杂度

// i 表示数组下标, base_address 表示数组首地址,data_type_size 表示数组中每个数据大小
a[i]_address = base_address + i * data_type_size

这里有一个注意点,我们是通过数组下标访问数据时,时间复杂度才是 O(1) ,当我们通过数据查找元素时,我们需要遍历数组查找对应的数据,时间复杂度是 O(n)。

二维数组

我们知道一维数组的空间地址肯定是连续的,那么我们的二维数组的地址呢?是不是也是连续的呢?

不同编程语言的内存管理是不一样的,以C++为例,在C++中二维数组是连续分布的。

我们来做一个实验,C++测试代码如下:

void test_arr() {
    int array[2][3] = {
    {0, 1, 2},
    {3, 4, 5}
    };
    cout << &array[0][0] << " " << &array[0][1] << " " << &array[0][2] << endl;
    cout << &array[1][0] << " " << &array[1][1] << " " << &array[1][2] << endl;
}
int main() {
    test_arr();
}

测试地址为

0x7ffee4065820 0x7ffee4065824 0x7ffee4065828
0x7ffee406582c 0x7ffee4065830 0x7ffee4065834

注意地址为16进制,可以看出二维数组地址是连续一条线的。

那么我们来看看Java的,也做一个实验。

public static void test_arr() {
    int[][] arr = {{1, 2, 3}, {3, 4, 5}, {6, 7, 8}, {9,9,9}};
    System.out.println(arr[0]);
    System.out.println(arr[1]);
    System.out.println(arr[2]);
    System.out.println(arr[3]);
}

输出的地址为:

[I@7852e922
[I@4e25154f
[I@70dea4e
[I@5c647e05

这里的数值也是16进制,这不是真正的地址,而是经过处理过后的数值了,我们也可以看出,二维数组的每一行头结点的地址是没有规则的,更谈不上连续。

结束

好了,数组的理论知识我们就讲解完了,接下开我们就要开始数组的刷题的,我是小六六,三天打鱼,两天晒网!

相关文章
|
1天前
|
算法
leetcode代码记录(寻找两个正序数组的中位数
leetcode代码记录(寻找两个正序数组的中位数
12 2
|
1天前
|
索引
leetcode代码记录(最长重复子数组
leetcode代码记录(最长重复子数组
10 0
|
1天前
leetcode代码记录(两个数组的交集
leetcode代码记录(两个数组的交集
9 1
|
1天前
leetcode代码记录(最大子数组和
leetcode代码记录(最大子数组和
10 2
|
1天前
|
算法 C++
【刷题】Leetcode 1609.奇偶树
这道题是我目前做过最难的题,虽然没有一遍做出来,但是参考大佬的代码,慢慢啃的感觉的真的很好。刷题继续!!!!!!
8 0
|
1天前
|
算法 索引
【刷题】滑动窗口精通 — Leetcode 30. 串联所有单词的子串 | Leetcode 76. 最小覆盖子串
经过这两道题目的书写,相信大家一定深刻认识到了滑动窗口的使用方法!!! 下面请大家继续刷题吧!!!
11 0
|
1天前
|
算法
【刷题】 leetcode 面试题 08.05.递归乘法
递归算法是一种在计算机科学和数学中广泛应用的解决问题的方法,其基本思想是利用问题的自我相似性,即将一个大问题分解为一个或多个相同或相似的小问题来解决。递归算法的核心在于函数(或过程)能够直接或间接地调用自身来求解问题的不同部分,直到达到基本情况(也称为基础案例或终止条件),这时可以直接得出答案而不必再进行递归调用。
25 4
【刷题】 leetcode 面试题 08.05.递归乘法
|
1天前
|
存储 算法 安全
【刷题】 leetcode 面试题 01.06 字符串压缩
来看效果: 非常好!!!过啦!!!
25 5
【刷题】 leetcode 面试题 01.06 字符串压缩
|
1天前
|
存储 算法 测试技术

热门文章

最新文章