数组
2.1理论基础
数组是连续存放在内存空间上的相同类型数据的集合
- 数组下标从0开始
- 数组内存空间联系
- 数组元素是不能删的,只能覆盖
vector底层实现是array,但不是数组是容器
C++中二维数组内存是连续的
2.2二分查找(最简单前提:数组为左右闭区间,有序且无重复元素)
- 例题1:给定一个n个元素有序的(升序)整型数组nums和一个目标值target,写出一个函数搜索nums中的target,如果目标存在返回1,否则返回-1.
解法1:C++的自定义数组解法
#include <iostream>
using namespace std;
int erFen(int a[],int n, int t) {
int mid, right = n - 1, left = 0;
while (left != right)
{
mid = (right + left) / 2;
if (a[mid] == t)
{
return mid;
}
else if (a[mid] < t)
{
left = mid + 1;
}
else if (a[mid] > t)
{
right = mid - 1;
}
}
return -1;
}
int main() {
int n,result;
cin >> n;
int* nums = new int[n];
cout << "please input the array:" << endl;
int i = 0, target;
for (i = 0; i < n; i++)
{
cin >> nums[i];
}
cout << "please input target:" << endl;
cin >> target;
result=erFen(nums,n, target);
cout << result << endl;
return 0;
}
解法2:力扣解题模式,只有关键代码
class Solution {
public:
int search(vector<int>& nums, int target) {
int right=nums.size()-1,left=0;
while(left<=right)//因为在双闭区间内,所以left==right是有意义的
{
int mid=(right+left)/2;//等同于(right-left)/2+left防止溢出
if(nums[mid]==target)
{
return mid;
}
else if(nums[mid]<target)
{
left=mid+1;//在[left,right]闭区间内,因为处于mid的值一定不是target,所以下一个left是mid+1
}
else
{
right=mid-1;//同理,mid的值一定不是target,所以right=mid-1
}
}
return -1;
}
};
- 写法二(数组为左闭右开区间)
class Solution {
public:
int search(vector<int>& nums, int target) {
int right=nums.size();//与上个方法不同
int left=0;
while(left<right){//left==right没有意义
{
int mid=(right+left)/2;//等同于(right-left)/2+left防止溢出
if(nums[mid]==target)
{
return mid;
}
else if(nums[mid]<target)
{
left=mid+1;//在[left,right)区间内,因为处于mid的值一定不是target,所以下一个left是mid+1
}
else
{
right=mid;//target在左区间[left,middle)内,所以right=mid
}
}
return -1;
}
};
- 例题2(35题):给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。请必须使用时间复杂度为 O(log n) 的算法。
①暴力解法:循环遍历数组是否有target,时间复杂度为O(n),空间复杂度为O(1)
②二分法(前提是有序数组,如果有重复元素则下标不唯一):左闭右闭区间(return left)、左闭右开区间(return right)
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
int left = 0, right = nums.size() - 1;
while (left <= right)
{
int mid = (right - left) / 2 + left;
if (nums[mid] == target)
{
return mid;
}
else if (nums[mid] > target)
{
right = mid - 1;
}
else
{
left = mid + 1;
}
}
return left;//return right+1;是相同的效果
}
};
2.3移除元素
- 例题1(题目27):给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。
不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
(数组中元素不能删去,只能覆盖)
①暴力解法:双循环,一层遍历数组,一层更新数组
②双指针法:在一层循环中,快指针找到非删除元素,慢指针记录新数组位置,完成两层循环的作用
//时间复杂度O(n^2)
//空间复杂度O(1)
#include "p.h"
int Solution1::removeElement(vector<int>& nums, int val) {
int i=0, len = 0, j;
int n = nums.size();
int k = 0;
while (k < n)
{
j = i;
if (nums[i] == val)
{
len++;
while (j < n - len)
{
nums[j] = nums[j + 1];
j++;
}
nums[n - len] = val;
k++;
}
else
{
i++;
k++;
}
}
return n - len;
}
// 时间复杂度:O(n)
// 空间复杂度: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(26题):给你一个 升序排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。
由于在某些语言中不能改变数组的长度,所以必须将结果放在数组nums的第一部分。更规范地说,如果在删除重复项之后有 k 个元素,那么 nums 的前 k 个元素应该保存最终结果。
将最终结果插入 nums 的前 k 个位置后返回 k 。
不要使用额外的空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。
class Solution {
public:
int removeDuplicates(vector<int>& nums) {
int expectedNums[nums.size()];
int t=0,j;
int i=0;
int w=0;
while(i<nums.size())
{
int flag=1;
expectedNums[t]=nums[i];
t++;
for(j=i+1;j<nums.size();j++)
{
if(nums[i]==nums[j])
{
flag=0;//如果有与当前元素相同的,则标志为0,且记录最后一个相同元素的位置
w=j+1;//将i置为最后相同元素的下一个位置
}
}
if(flag==1)//如果遍历后没有相同的,则将i加1
{
i=i+1;
w=i;
}
i=w;//记录i的位置
}
for(int i=0;i<t;i++)
{
nums[i]=expectedNums[i];
}
return t;
}
};
- 例题3(283题):给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
请注意 ,必须在不复制数组的情况下原地对数组进行操作。
//此方法覆盖数组元素后重写0,如果是{0,0,0.....0,1}的数组,则需要从1到N-1重写0,效率不高
#include "p.h"
void Solution1:: moveZeroes(vector<int>& nums) {
int low = 0, fast = 0;
int n = nums.size();
for (fast = 0; fast < n; fast++)
{
if (nums[fast] != 0)
{
nums[low++] = nums[fast];
}
}
for (int i = low; i < n; i++)
{
nums[i] = 0;
}
cout << "[";
for (int i = 0; i < n; i++)
{
if (i != n - 1)
cout <<nums[i] << ",";
else
cout << nums[i] << "]"<<endl;
}
}