文章目录
今日记录
数组理论基础
知识记录:
- 存放在连续内存空间上的相同类型数据的集合。
- 数组下标都是从0开始的 —— 增减元素时要移动其余的元素地址。
- vector array的区别:vector的底层实现是array,严格来讲vector是容器,不是数组。
- 数组的元素是不能删的,只能覆盖。
- 二维数组也是连续分布的:先行后列存放地址。
704. 二分查找
题目:给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。
1.二分法查找理论记录
查找基础
有序数组且无重复元素
思路
定义left=0,right=numsize-1为左右边界索引,middle=(left+right)/2为中间值索引,比较target值与nums[middle]的值是否相等,根据二分搜索的思路更新每一次搜索的区间。
关键点
- while ( left < right ) or while ( left <= right )
- 更新区间左右边界时 right = middle or right = middle - 1 (left = middle or left = middle + 1)
两种情况讨论:
1. 左闭右闭 [left, right]
关键点1:此时若取”=“,[ left, right ] 区间合法( EX : [1, 1] ),所以取 while ( left <= right )
关键点2:判断条件为 if ( nums[middle] > target ),target一定无法取到nums[middle],结合左闭右闭区间的条件,所以 right = middle - 1 ( [ left, middle-1 ] )
2. 左闭右开 [left, right)
关键点1:此时若取”=“,[ left, right ) 区间不合法( EX : [1, 1) ),所以取 while ( left < right )
关键点2:判断条件为 if ( nums[middle] > target ),target一定无法取到nums[middle],但此时是左闭右开区间,本来就无法取到右边界,所以 right = middle ( [ left, middle ) )
2.代码实现(以左闭右闭为例)
class Solution {
public:
int search(vector<int>& nums, int target) {
int left = 0;
int right = nums.size() - 1;
int middle;
while (left <= right) {
middle = (left + right) / 2;
if (nums[middle] > target) {
right = middle - 1;
} else if (nums[middle] < target) {
left = middle + 1;
} else
return middle;
}
return -1;
}
};
3.复杂度:
时间复杂度:时间复杂度的计算并不是计算程序具体运行的时间,而是算法执行语句的次数。
空间复杂度:空间复杂度是对一个算法在运行过程中临时占用存储空间大小的量度
对于二分法,假设共有n个元素,查找区间为 n/2, n/4, n/8,…,n/2^k,k为执行次数即为时间复杂度,k最大时区间最小为1,令
n/2^k=1,解出k=log2n (2为底n的对数)
27. 移除元素
题目:给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素。元素的顺序可能发生改变。然后返回 nums 中与 val 不同的元素的数量。
双层for循环实现
时间复杂度:两个for循环为O(n^2)
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int size = nums.size();
for (int i = 0; i <= size - 1; i++) {
if (nums[i] == val) {
for (int j = i + 1; j <= size - 1; j++) {
nums[j - 1] = nums[j];
}
i--;
size -= 1;
}
}
return size;
}
};
双指针思路
明确快慢指针到底指向的什么:
快指针(fast)代表的是新数组中的元素(本题中代表nums[fast] != val 的值);
慢指针(slow)代表的是新数组的下标(令num[slow] = nums[fast])
时间复杂度:单个for循环为O(n)
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int fast;
int slow = 0;
for (fast = 0; fast < nums.size(); fast++) {
if (nums[fast] != val) {
nums[slow] = nums[fast];
slow++;
}
}
return slow;
}
};
细节注意:fast < nums.size() 和 fast <= nums.size()-1 没什么区别,那为什么第二个会在空数组时报数组越界的错误?
vector的size()函数返回值是无符号整数,空数组时返回了0,再减个一会溢出
总结
今日学习时长2小时,彻底搞懂了