《数组》
Definition:数组是存放在连续内存空间上的相同类型数据的集合。
需要两点注意的是
- 数组下标都是从0开始的。
- 数组内存空间的地址是连续的
正是因为数组的在内存空间的地址是连续的,所以我们在删除或者增添元素的时候,就难免要移动其他元素的地址。
如果使用C++的话,要注意vector 和 array的区别,vector的底层实现是array,严格来讲vector是容器,不是数组。
数组的元素是不能删的,只能覆盖。
Note: 在C++中二维数组在地址空间上是连续的。Java是没有指针的,同时也不对程序员暴露其元素的地址,寻址操作完全交给虚拟机。
《二分法》
使用condition:1.有序数组 2.无重复元素
两种方法(根据区间)
大家写二分法经常写乱,主要是因为对区间的定义没有想清楚,区间的定义就是不变量。要在二分查找的过程中,保持不变量,就是在while寻找中每一次边界的处理都要坚持根据区间的定义来操作,这就是循环不变量规则。
写二分法,区间的定义一般为两种,左闭右闭即[left, right],或者左闭右开即[left, right)。
给定一个 n
个元素有序的(升序)整型数组 nums
和一个目标值 target
,写一个函数搜索 nums
中的 target
,如果目标值存在返回下标,否则返回 -1
。
示例 1:
输入:nums
= [-1,0,3,5,9,12],target
= 9 输出: 4 解释: 9 出现在nums
中并且下标为 4
#1 闭区间 时间O(log2 N)
class Solution {
public:
int search(vector<int>& nums, int target) {
int left = 0;
int right = nums.size()-1 ; //闭区间
while (left <= right){
int middle = left + (right-left)/2;
if(nums[middle]<target){
left = middle+1;
}else if(nums[middle]>target){
right = middle-1;
}else {return middle;}
}
return -1;
}
};
#2开区间
class Solution {
public:
int search(vector<int>& nums, int target) {
int left = 0;
int right = nums.size() ; //开区间
while (left < right){
int middle = left + ((right-left)>>1);
if(nums[middle]<target){
left = middle+1;
}else if(nums[middle]>target){
right = middle;
}else {return middle;}
}
return -1;
}
};
总结:
1.闭区间中指针位置即索引位置,开区间右指针要多一个单位。
2.在循环过程条件不同。
3.指针移动变化不同。
《移除元素》
示例 1:
输入:nums = [3,2,2,3], val = 3 输出:2, nums = [2,2] 解释:函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。你不需要考虑数组中超出新长度后面的元素。例如,函数返回的新长度为 2 ,而 nums = [2,2,3,3] 或 nums = [2,2,0,0],也会被视作正确答案。
示例 2:
输入:nums = [0,1,2,2,3,0,4,2], val = 2 输出:5, nums = [0,1,4,0,3]
1.双指针 时间O(N) space O(1)
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int slowindex = 0;
for(int fastindex = 0;fastindex < nums.size();fastindex++){
if(val != nums[fastindex]){
nums[slowindex++]=nums[fastindex];
}
}
return slowindex;
}
};
2.反向指针 时间O(N) space O(1)
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int leftIndex = 0;
int rightIndex = nums.size() - 1;
while (leftIndex <= rightIndex) {
// 找左边等于val的元素
while (leftIndex <= rightIndex && nums[leftIndex] != val){
leftIndex ++;
}
// 找右边不等于val的元素
while (leftIndex <= rightIndex && nums[rightIndex] == val) {
rightIndex --;
}
// 将右边不等于val的元素覆盖左边等于val的元素
if (leftIndex < rightIndex) {
nums[leftIndex++] = nums[rightIndex--];
}
}
return leftIndex;
}
};
Note:
a[i++] = a[2] 在这里是先进行a[i] = a[2]的赋值操作,再对i进行加一操作。
a[++i] = a[2] 在这里是先进行i加一操作,再进行a[i] = a[2]的赋值操作。