数组是在程序设计中,把具有相同类型的若干元素按有序的形式组织起来的一种形式。
作为线性表的实现方式之一,数组中的元素在内存中是 连续 存储的,且每个元素占相同大小的内存。
数组通过 索引 快速访问每个元素的值。在大多数编程语言中,索引从 0 算起。
在不同的编程语言中,数组的实现方式具有一定差别。比如 C++ 和 Java 中,数组中的元素类型必须保持一致,而 Python 中则可以不同。相比之下,Python 中的数组(称为 list)具有更多的高级功能。
1. 两数之和
1.1 最直观的解法,也是最容易想到的算法,暴力遍历
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
vector<int> answer;
//将数组中的每一个元素都和后面的元素一一配对比较,时间复杂度是
//(n-1)+(n-2)+(n-3)+...+1 = [(n-1)/2]*n = O(n^2)
//空间复杂度,除了表达问题所需要的存储空间,另外借助了两个int变量
//和一个确定为0或2个元素的数组,所以是常数级的复杂度,即O(1)
for(int i=0;i<nums.size()-1;i++){
for(int j=i+1;j<nums.size();j++){
if(nums[i]+nums[j] == target){
answer.push_back(i);
answer.push_back(j);
return answer;
}
}
}
//若不存在符合条件的元素,则返回空的下标数组
return answer;
}
};
1.2 你可以想出一个时间复杂度小于 O(n2)
的算法吗?
多学点,后面回过头来再看(掩盖不了我的菜了😭)
这里使用双指针需要提前对数组进行排序
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
vector<int> answer;
//。。。。。。。。。。//
//用双指针,将时间复杂度降为O(n),需要先对nums进行排序才行
int i = 0;
int j = nums.size()-1;
while(i!=j){
//如果找到了符合条件的元素,将其下标放入返回数组,跳出循环
if(nums[i]+nums[j]==target){
answer.push_back(i);
answer.push_back(j);
break;
}
//若不符合条件,判断当前结果是否大于目标值
//若大于,则移动数值大的指针
if(nums[i]+nums[j]>target){
if(nums[i]>nums[j]){
i++;
}else{
j--;
}
}else{ //若小于,则移动数值小的指针
if(nums[i]<nums[j]){
i++;
}else{
j--;
}
}
}
return answer;
}
};
2. 盛最多水的容器
2.1 最直观的解法,也是最容易想到的算法,暴力遍历(超出时间限制了🚫)
class Solution {
public:
int maxArea(vector<int>& height) {
//假设这两条线是第i和j条,那么它们围成的面积是
//|j-i|*min(height(i),height(j))
int max = -1;
int mh;
//暴力破解,每两个元素都试一遍,时间复杂度是O(n^2)
//空间复杂度,O(1)
for(int i=0;i<height.size()-1;i++){
for(int j=i+1;j<height.size();j++){
//找高度小的
if(height[i]<=height[j]){
mh = height[i];
}else{
mh = height[j];
}
//计算面积
int area = (j-i)*mh;
if(area>max){
max = area;
}
}
}
return max;
}
};
2.2 从算法上改进时间复杂度为O(n)
一个一个试没必要,我们从公式出发,目的是找到最大的面积,面积由底长和高度决定。可以用两个指针指向数组的一头一尾,慢慢靠里面移动,这就保证了底长一直是最大的,再移动高度值小的指针(🤔)。
class Solution {
public:
int maxArea(vector<int>& height) {
//使用双指针,时间复杂度O(n)
//空间复杂度依然是O(1)
int i=0;
int j=height.size()-1;
int max = -1;
int len;
int h;
int area;
while(i!=j){
len = j-i;
h = height[j];
if(height[i]<height[j])
h = height[i];
//求面积
area = len*h;
if(area>max){
max = area;
}
if(height[i]<height[j]){
i++;
}else{
j--;
}
}
return max;
}
};
这么一看,两数之和好像也可以用双指针
(看来数组里面运用双指针对于减少算法复杂度很有效)
3. 寻找两个正序数组的中位数
要从问题本身的特点出发,算法也是因题而异的
本来想着先合并再找中位数的,但是合并两个排好序的数组也是需要O(m+n)的时间复杂度的。要求算法的时间复杂度为 O(log(m+n)),这是对数级别的复杂度,首先就要想到要有除以2的操作了。2^k = m+n,k=log(m+n)。
中位数就是排在中间位置的数,或取中间两个数的平均值。
一般找规律都可以用特殊情况来找,两个数组分别求中位数,小的去掉左部分继续求,大的去掉右部分继续求,直到两个数组的中位数一致。