【数据结构与算法】2.1 数组简介

2. 数组和字符串

2.1 数组简介

2.1.1 集合、列表和数组

集合特性:集合里的元素类型不一定相同,集合里的元素没有顺序

列表/线性列表:是一种数据项构成的有限序列,即按照一定的线性顺序,排列而成的数据项的集合。列表最常见的表现形式有数组和链表,而我们熟悉的栈和队列则是两种特殊类型的列表。列表中没有索引。列表中的元素在内存中可能彼此相邻,也可能不相邻。

数组:数组是列表的实现方式之一。数组索引从 0 开始。数组中的元素在内存中是连续存储的,且每个元素占用相同大小的内存。

2.1.2数组的操作

读取元素

通过索引读取元素,它的时间复杂度是常数级别,为 O(1)。

查找元素

在查找元素时,只需从数组开头逐步向后查找就可以了。最坏情况下,搜索的元素为 “R”,或者数组中不包含目标元素时,我们需要查找 n 次,n 为数组的长度,因此查找元素的时间复杂度为O(N)。

插入元素

如果需要频繁地对数组元素进行插入操作,会造成时间的浪费。事实上,另一种数据结构链表,可以有效解决这个问题。

删除元素

当数组的长度为 n 时,最坏情况下,我们删除第一个元素,共需要的步骤数为 1 + (n - 1) = n 步,其中,1 为删除操作,n - 1 为移动其余元素的步骤数。删除操作具有线性时间复杂度,即时间复杂度为O(N)。(N为数组长度)

2.1.3例题

例1:寻找数组的中心索引

给你一个整数数组 nums ,请计算数组的 中心下标 。

数组 中心下标 是数组的一个下标,其左侧所有元素相加的和等于右侧所有元素相加的和。

如果中心下标位于数组最左端,那么左侧数之和视为 0 ,因为在下标的左侧不存在元素。这一点对于中心下标位于数组最右端同样适用。

如果数组有多个中心下标,应该返回 最靠近左边 的那一个。如果数组不存在中心下标,返回 -1 。

class Solution {
public:
    int pivotIndex(vector<int> & nums) {
        int sum = 0;
        for(int num: nums){
            sum+= num;
        }
        int leftSum = 0;
        int rightSum = sum - nums[0];
        if(leftSum == rightSum) {
            return 0;
        }
        for(int i = 1; i < nums.size(); i++) {
            leftSum += nums[i - 1];
            rightSum -= nums[i];
            if(leftSum == rightSum) {
                return i;
            }
        }
        return -1;
    }  
};
// 思路:要计算数组的中心下标,可以使用双指针的方法。首先,计算整个数组的总和。然后,初始化左侧和为0,右侧和为总和减去第一个元素的值。接下来,从数组的第一个元素开始遍历,每次迭代更新左侧和和右侧和,并检查左侧和是否等于右侧和。如果相等,则当前下标即为中心下标。如果遍历完整个数组后仍未找到中心下标,则返回-1。

例2:搜索插入位置

给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。

请必须使用时间复杂度为 O(log n) 的算法。

class Solution {
public:
    int searchInsert(vector<int>& nums, int target) {
        int left = 0;
        int right = nums.size() - 1;
        while(left <= right) {
            int mid = left + (right - left) / 2;
            if(nums[mid] == target){
                return mid;
            }else if(nums[mid] < target){
                left = mid + 1;
            } else {
                right = mid - 1;
            }
        }
        return left;
    }
};
// 在考虑时间复杂度为 O(log n) 的算法时,通常需要使用二分查找的思想。二分查找算法的基本思想是:对于有序数组,我们可以将查找的范围不断缩小一半,直到找到目标值或确定它应该插入的位置。前提:数组已经有序(从小到大)。

/* 具体实现二分查找算法时,通常按以下步骤进行:

初始化左边界 left 为数组的起始位置,右边界 right 为数组的结束位置。
在每一次循环中,计算中间位置 mid = (left + right) / 2。
比较中间位置的值与目标值的大小:
如果中间位置的值等于目标值,则返回中间位置。
如果中间位置的值大于目标值,则将右边界 right 更新为 mid - 1。
如果中间位置的值小于目标值,则将左边界 left 更新为 mid + 1。
重复步骤2和步骤3,直到左边界 left 大于右边界 right。

计算中间位置时会使用 (left + right) / 2 的方式,其中 left 是左边界,right 是右边界。

然而,当 left 和 right 非常大的时候,它们的和可能会超过整数的表示范围,导致溢出的错误。

为了避免这种情况,我们可以使用 (left + right) / 2 的等价形式 left + (right - left) / 2 来计算中间位置。

这种方式先计算了 right - left,即边界的差值,然后再将其除以 2,最后加上 left 得到中间位置。 */

例3:合并区间

以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi] 。请你合并所有重叠的区间,并返回 一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间 。

// 二维容器
vector<vector<int>> mergeIntervals(vector<vector<int>>& intervals) {
    if (intervals.empty()) {
        return {};
    }

    // 按照区间的起始位置进行排序
    sort(intervals.begin(), intervals.end(), [](const vector<int>& a, const vector<int>& b) {
      // 根据每一个元素的迭代器的第一个元素来排序
        return a[0] < b[0];
    });

    // 定义空的二维容易,并将第一个元素放入
    vector<vector<int>> mergedIntervals;
    mergedIntervals.push_back(intervals[0]);

    for (int i = 1; i < intervals.size(); i++) {
        // 如果当前区间的起始位置小于等于前一个区间的结束位置,说明存在重叠
        // mergedIntervals.back()[1] 表示二维容器 mergedIntervals 中最后一个子向量(一维容器)的第二个元素
        if (intervals[i][0] <= mergedIntervals.back()[1]) {
            // 合并区间,更新前一个区间的结束位置
            mergedIntervals.back()[1] = max(mergedIntervals.back()[1], intervals[i][1]);
        } else {
            // 当前区间与前一个区间不重叠,将当前区间添加到结果数组中
            mergedIntervals.push_back(intervals[i]);
        }
    }

    return mergedIntervals;
}

int main() {
    vector<vector<int>> intervals = {{1, 3}, {2, 6}, {8, 10}, {15, 18}};

    vector<vector<int>> merged = mergeIntervals(intervals);

    // 输出合并后的区间
    for (const auto& interval : merged) {
      // 依次输出每一个二维容器中的每个元素迭代器的区间范围
        cout << "[" << interval[0] << ", " << interval[1] << "] ";
    }
    //[1, 6] [8, 10] [15, 18]
    cout << endl;
    return 0;
}

你可能感兴趣的:(数据结构与算法,算法,数据结构)