一、定义
顺序表是指用一组地址连续的储存单元依次存储数据的顺序存储结构。
在c++STL中靠容器vector实现,其底层为数组。
二、顺序表的优缺点
1. 优点
1). 空间利用率高,无需为表示表中元素关系而增加额外的存储空间
2). 按索引随机访问元素的效率高,可达O(1)
2. 缺点
1). 插入和删除时需要移动大量元素
2). 必须一开始就确定所需存储空间的容量
三、顺序表的相关算法
1. 线性枚举
枚举数组中的每个元素做出相应判断(比较大小等),也就相当于遍历。
2. 前缀和差分
通过前缀和数组求取原数组区间[ l, r ](闭区间或其他)上元素和。计算的时间复杂度为O(1)。
int sum[maxn];
int* prefixSum(int* nums, int numsSize, int m, int *l, int *r){
int i;
int *ret;
sum[0] = nums[0]; // (1)
for(i = 1; i < numsSize; ++i) {
sum[i] = sum[i-1] + nums[i];
}
ret = (int *) malloc( m * sizeof(int) ); // (2)
for(i = 0; i < m; ++i) {
int leftsum = l[i]==0? 0 : sum[l[i]-1]; // (3)
int rightsum = sum[r[i]];
ret[i] = rightsum - leftsum; // (4)
}
return ret;
}
· (1) 对下标0的特殊处理防i-1越界
· (2) 需要返回的数组
· (3) 同(1)
· (4) 差分计算
3.双指针问题
题目
给定一个长度为n的连续字符串,求出最长的一个连续不重复的子字符串。
维护两个指针 i 和 j ,区间 [ i , j ] 内的元素没有重复,若有重复 i++,否者 j++,直到j不能增加为止。
此过程中,可以利用哈希表来维护没有重复元素,并记录下来 j - i +1的最大值。
int getmaxlen(int n, char *str, int& l, int& r) {
int ans = 0, i = 0, j = -1, len; // 1)
memset(h, 0, sizeof(h)); // 2)
while (j++ < n - 1) { // 3)
++h[ str[j] ]; // 4)
while (h[ str[j] ] > 1) { // 5)
--h[ str[i] ];
++i;
}
len = j - i + 1;
if(len > ans) // 6)
ans = len, l = i, r = j;
}
return ans;
}
此算法中i j 两个指针分别最多自增n次,并且二者自增独立,并非相加相乘的关系,时间复杂度为O(n)。
4. 二分查找
针对有序数组,我们可以和区间中点值的比较进行判断。
int search(int *nums, int numsSize, int target) {
int l = 0, r = numsSize - 1; // (1)
while(l <= r) { // (2)
int mid = (l + r) >> 1; // (3)
if(nums[mid] == target) {
return mid; // (4)
}else if(target > nums[mid]) {
l = mid + 1; // (5)
}else if(target < nums[mid]) {
r = mid - 1; // (6)
}
}
return -1; // (7)
}
四、题目
1588. 所有奇数长度子数组的和
思路一 利用双指针,从 i 开始枚举所有的 j - i +1 %2 == 1的情况。
int sumOddLengthSubarrays(vector<int>& arr) {
int n = arr.size(),ans = 0;
for(int i = 0;i < n;++i){
int sum = 0;
for(int j = i;j < n;++j){
sum += arr[j]; ///效果比前缀和数组更好
if((j-i+1) & 1){ // 位运算
ans += sum;
}
}
}
return ans;
}
思路二 利用数学关系,直接让 i 以步幅2变化。
int sumOddLengthSubarrays(vector<int>& arr) {
int sum[arr.size()+1],i,ans = 0;
sum[0] = arr[0];
for(i = 1;i < arr.size();++i){
sum[i] = arr[i] + sum[i-1];
}
i = 1;
while(i <= arr.size()){
int j;
ans += sum[i - 1];
for(j = 0;j + i < arr.size();++j){
ans += sum[j+i] - sum[j];
}
i+=2;
}
return ans;
}
1640. 能否连接形成数组
这个题目就纯暴力,利用双指针法,一个指针指向数组arr,另一个指针指向二维数组pieces,不断地搜索,对比,最终能完全匹配返回true;否则,返回false。
bool canFormArray(vector<int>& arr, vector<vector<int>>& pieces) {
for(int i = 0;i < arr.size();++i)
{
int flag = 1;
for(int j = 0;j < pieces.size();++j)
{
if(arr[i] == pieces[j][0])
{
flag = 0;
for(int k = 0;k < pieces[j].size();++k)
{
if(arr[i] != pieces[j][k])
return false;
if(k + 1 != pieces[j].size())
++i;
}
break;
}
}
if(flag)
return false;
}
return true;
}
```