前言
我在leetcode上刷了一些算法和学习了c++语法后,经常对c++中的一些基础操作不太熟练,如链表的插入、删除、遍历二叉树等,这些操作对我来说应该熟记于心,滚瓜烂熟。
一、数组的定义及相关操作
1.数组是一块连续的内存,并按照顺序存储数据,创建数组时,需要先指定数组的容量大小,在根据大小分配内存,因为需要先进行内存的分配,所以数据的空间利用率不高,经常有空闲的区域。
2.数组可以看成是一个哈希表,其下标为Key,下表对应的数据为Value,可以使用时间复杂度O(1)进行查找
3.C++中的STL中的vector,就是一个动态数组,vector和普通数组的区别是,vector是动态分配内存的,每次扩充内存,是前一次的两倍
1.1 数组的声明
数组的声明需要指定数据类型和元素数量
类型 名称 [ 元素数量 ];
double balance [10];
1.2 数组的初始化
double balance[5] = {10.0, 5, 5.0, 2.0, 3.0}
1.3 vector——c++中的特殊数组(比数组好用的数组)
vector不光数组的大小是可以灵活设置的,还有很多相关的函数可以使用
vector的定义: vector<int> vector_name
size():返回向量中元素的个数。
push_back(value):将一个元素添加到向量的末尾。
pop_back():删除向量末尾的元素。
insert(position, value):在指定位置插入一个元素。
erase(position):删除指定位置的元素。
clear():删除向量中的所有元素。
empty():检查向量是否为空,返回一个布尔值。
front():返回向量中第一个元素的引用。
back():返回向量中最后一个元素的引用。
at(index):返回指定索引位置的元素的引用,带有边界检查。
resize(new_size):改变向量的大小,可以增加或减少元素的数量。
reserve(new_capacity):改变向量的容量,实际上并不改变向量的大小。
swap(other_vector):交换两个向量的内容。
begin() 和 end():返回指向向量首元素和尾后元素的迭代器。
1.3 题目1:返回数组中重复的数字(力扣442题)
题目描述:给你一个长度为 n 的整数数组 nums ,其中 nums 的所有整数都在范围 [1, n] 内,且每个整数出现 一次 或 两次 。请你找出所有出现 两次 的整数,并以数组形式返回。
1.3.1 完成代码1——原地哈希
时间复杂度o(n),空间复杂度o(1)
#include<iostream>
#include<string>
#include <vector>
using namespace std;
vector <int> find_fuc(vector<int> &nums)
{
int nums_len = nums.size();
int n = nums_len;
vector<int> ret;
for (auto &num : nums)
{
int x = (num - 1) % nums_len;
nums[x] += nums_len;
}
while (n-- > 0)
{
if (nums[n] > 2 * nums_len) ret.push_back(n);
return ret;
}
void test1()
{
//vector<int> nums = { 10,2,8,9,10,10,10,7,3,2,5 ,7};
vector<int> nums = {};
int nums_len = nums.size();
vector<int> results = find_fuc(nums);
cout << "重复的数据为:";
for (const auto& result : results)
{
cout << (result+1) % nums_len << " ";
}
}
int main()
{
test1();
return 0;
}
1.3.1.1代码中相关命令的学习
-
auto:auto是关键字,可以自动推导数据类型,好处是简化代码,提高代码的可读性
auto num = 10;
auto name = “zzy” -
const auto& result : results
这段代码中声明了result变量,该变量每次从results中引用一个值,使用 & 的目的是不对results进行拷贝,直接使用,可以节省空间。使用const关键字的目的是只能读取result的值,不能进行修改,保证代码的健壮性。 -
for (const auto& result : results)
这里的 for(int result:results),是一种范围基本循环,results可以是数组、向量、列表等容器,每次将容器中的内容传输到result。 -
ret.push_back(n)
每次向ret向量中的尾部传入一个值
1.3.2完成代码二——哈希表
时间复杂度o(n),空间复杂度o(n)
创建一个动态数组当作哈希表
#include<iostream>
#include<string>
#include <vector>
using namespace std;
vector <int> find_fuc(vector<int> &nums)
{
int nums_len = nums.size();
int n = 0;
int* countings = new int[nums_len]();
//int countings[nums_len] = {0};
vector<int> ret;
for (int &num : nums)
{
int x = num - 1;
countings[x] += 1;
}
for(int i = 0; i < nums_len; i++)
{
n++;
if (countings[i] >= 2) ret.push_back(n);
// cout << n <<":"<< nums[n]<< endl;
}
delete[] countings;
return ret;
}
void test1()
{
// vector<int> nums = { 10,2,8,9,10,10,10,7,3,2,5 ,7};
vector<int> nums = {1,1,1,1,1,5,5,3,1,5,3,4,5,6,9,9};
int nums_len = nums.size();
vector<int> results = find_fuc(nums);
cout << "重复的数据为:";
for (const auto& result : results)
{
cout << result % nums_len << " ";
}
}
int main()
{
test1();
return 0;
}
1.3.2.1代码内容学习
上述代码,我在运行时出现了一些问题
问题1:
定义数组时出错,报错原因时数组定义时,nums_len是一个变量导致的,而数组的空间大小,是需要在编译的时候就定义好的
相关代码: int countings[nums_len] = {0};
解决方法,设置一个动态数组
动态数组的设置命令 int* countings = new int[nums_len]();
使用动态数组的时候要注意,使用完成后一定要手动释放空间,不然会造成内存泄漏
释放空间命令 delete[] countings;
在这里,出现的c++内存分配的情况,在大型项目中,需要合理的分配内存的使用情况,而堆(heap)时由开发人员手动进行分配和释放的,在使用时非常灵活,所以一些大型数据或对象中,经常使用堆的方式来创建
使用new在堆上创建对象的几种方式
创建单个对象: MyClass* obj = new MyClass;
创建对象数组: MyClass* objArray = new MyClass[5];
创建对象并初始化: MyClass* obj = new MyClass(42);
使用delete释放内存的方式:
释放对象: delete obj;
释放对象数组: delete[] objArray;
问题2:
无法使用范围-based for 循环传递数据,也就是这种形式:for (const auto& counting : countings)
因为countings是针类型,不是数组、容器、列表、字符串的形式,所以不能用
1.4多维数组
多维数组的定义:type name[size1][size2][size3];
定义一个整型的二维数组:int threedim[2][2] = {{1,2},{4,5}}
1.4.1 题目:二维数组中的查找
在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的个二维数组和一个整数,判断数组中是否含有该整数。
#include<iostream>
#include<string>
#include <vector>
using namespace std;
bool Find(int* matrix, int rows, int columns, int number)
{
bool found = false;
if (matrix != nullptr && rows > 0 && columns > 0)
{
int row = 0;
int column = columns - 1;
while (row < rows && column >= 0)
{
//cout << "matrix[row * columns + column]:" << matrix[] << endl;
if (matrix[row * columns + column] == number)
{
found = true;
break;
}
else if (matrix[row * columns + column] > number)
--column;
else
++row;
}
}
return found;
}
void Test1()
{
int matrix[][4] = { {1, 2, 8, 9}, {2, 4, 9, 12}, {4, 7, 10, 13}, {6, 8, 11, 15} };
cout << Find((int*)matrix, 4, 4, 16) << endl;
}
int main()
{
Test1();
return 0;
}
1.4.1.1 代码中遇到的问题
1.如果输入的二维数组是空的,那么在判断的时候就需要设置空指针的判断
判断空指针:if (matrix != nullptr)
这里的nullptr常用于初始化空类型的指针
2.为什么Find函数中可以使用 if (matrix[row * columns + column] == number)来判断二位数组对应位置是否等于指定数,而在find函数外部,matix[nums]输出的却是地址?
这是因为Find(int* matrix, int rows, int columns, int number)输入的二维数组的指针,也就是首地址,所以在Find函数内部输出martix[num]输出的是int类型的值,而Find函数外部,使用martix[num]输出的是二维数组中的num行的首地址。
Leetcode题目:长度最小的子数组
这道题用滑动窗口解决,但是跟我理解的滑动窗口是有区别的,滑动窗口随时可变,很巧妙
https://assets.leetcode-cn.com/solution-static/209/1.png
这个是图片的链接,可以看看