1.集合、列表和数组
集合一般被定义为:由一个或多个确定的元素所构成的整体。 通俗来讲,集合就是将一组事物组合在一起。你可以将力扣的题库看作一个集合。
集合有什么特性呢? 集合里的元素类型不一定相同;集合里的元素没有顺序
列表(又称线性列表)的定义为:是一种数据项构成的有限序列,即按照一定的线性顺序,排列而成的数据项的集合。
列表的概念是在集合的特征上形成的,它具有顺序,且长度是可变的。
数组是列表的实现方式之一,也是面试中经常涉及到的数据结构。那么如何从宏观上区分列表和数组呢?这里有一个重要的概念:索引。
其次,数组中的元素在内存中是连续存储的,且每个元素占用相同大小的内存。相反,列表中的元素在内存中可能彼此相邻,也可能不相邻。
2. 数组的操作
共4种操作方式:读取、查找、插入、删除
读取:读取数组中的元素,即通过数组的索引访问数组中的元素。这里的索引其实就是内存地址,计算机可以跳跃到任意的内存地址上,这就意味着只要计算出数组中元素的内存地址,则可以一步访问到数组中的元素。对于数组,计算机会在内存中申请一段 连续 的空间,并且会记下索引为 0
处的内存地址。
时间复杂度: O(1)
查找:计算机只会保存数组中索引为 0
处元素的内存地址,因此当计算机想要知道数组中是否包含某个元素时,只能从索引 0
处开始,逐步向后查询。
最坏情况下时间复杂度:O(N)
插入:如果要将该元素插入到数组的末尾,只需要一步。即计算机通过数组的长度和位置计算出即将插入元素的内存地址,然后将该元素插入到指定位置即可。
如果要将该元素插入到数组中的其他位置,则会有所区别,这时我们首先需要为该元素所要插入的位置腾出
空间,然后进行插入操作。从插入位置之后的元素都要向后移动,然后插入该元素。
删除:删除元素与插入元素的操作类似,当我们删除掉数组中的某个元素后,数组中会留下 空缺 的位置,而数组中的元素在内存中是连续的,这就使得后面的元素需对该位置进行 填补 操作。
3. 数组的中心索引
中心索引 :数组中心索引的左侧所有元素相加的和等于右侧所有元素相加的和。
输入:
nums = [1, 7, 3, 6, 5, 6]
输出:3
解释:索引 3 (nums[3] = 6) 的左侧数之和 (1 + 7 + 3 = 11),与右侧数之和 (5 + 6 = 11) 相等。同时, 3 也是第一个符合要求的中心索引。
从数学上可得: 首先,计算整个数组的和,记为sum;然后计算左边 i-1 个值的和为sumleft,则右边的和sumright为sum - sumleft - nums[i], 若sumleft = sumright,返回 i 即可。
int pivotIndex(vector<int>& nums) {
int sum = 0; int left = 0; int right = 0;
for(int i:nums)
{
sum += i;
}
//cout << sum << endl;
for(int i=0; i<nums.size(); i++){
if(i == 0) {left = 0;}
else
left += nums[i - 1];
right = sum - left - nums[i];
if(left == right)
return i;
}
return -1;
}
4.搜索插入位置
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
示例 1:
输入: [1,3,5,6], 5
输出: 2
示例 2:输入: [1,3,5,6], 2
输出: 1
示例 3:输入: [1,3,5,6], 7
输出: 4
示例 4:输入: [1,3,5,6], 0
输出: 0
int searchInsert(vector<int>& nums, int target) {
if(nums.empty()) return -1;
for(int i=0; i<nums.size(); i++){
if(nums[i] == target)
return i;
}
nums.push_back(target);
sort(nums.begin(), nums.end());
return searchInsert(nums, target);
}