0%

leetcode刷题

数组

简单

1.两数之和

image-20240305100410526

我的算法思想:

通过遍历两次数组计算每两个元素的和,找到一对与target相等的元素返回即可。

1
时间复杂度:O(n^2)

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
vector<int> ans;
for(int i = 0;i < nums.size() - 1;i++)
{
for(int j = i + 1;j < nums.size();j++)
{
if(nums[i] + nums[j] == target)
{
ans = {i,j};
return ans;
}
}
}
return ans;
}
};
学习:
1.Vector作为C++中的动态数组容器,可以容纳多种数据类型,支持随机存储;定义及初始化操作:
vector v1 v1是一个元素类型为T的空容器
vector v2(v1) 使用v1中的元素初始化v2
vector v2 = v1 同上
vector v3(n,val) v3中包含n个值为val的元素
vector v4 {a,b,c…} 使用a,b,c…初始化v4
vector> matrix(M,vector(N)) 二维数组初始化
vector v5(n) v5中包含n个默认值的初始化元素

常用操作:

v1 = {a,b,c…} 用元素{a,b,c….}替代v1中元素
2.寻找更优的算法:

利用哈希表可以将寻找 target - x 的时间从O(N)降到O(1);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int,int> hashtable;
for(int i = 0;i < nums.size();i++)
{
auto it = hashtable.find(target - nums[i]);
if(it != hashtable.end())
{
return {it->second,i};
}
hashtable[nums[i]] = i;
}
return {};
}
};

注意:C++中哈希表find()函数是以key键值作为参数寻找哈希表中元素,对于本题应该将x的值作为key,对应index索引值作为指向值。

26.删除有序数组中的重复项

思想

利用两个指针遍历有序数组,如果快指针与慢指针值相同,快指针后移;不同,则将快指针指向的值赋给慢指针,然后慢指针后移,直到快指针走到最后。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution {
public:
int removeDuplicates(vector<int>& nums) {
int n = nums.size();
if(n == 0)
{
return 0;
}
int index = 0;
for(int i = 1;i < nums.size();i++)
{
if(nums[i] != nums[index])
{
nums[++index] = nums[i];
}
}
return index + 1;
}
};
注意:

1.题目中提示有判断结果的方式,根据算法的返回值来比对对应长度的数组是否相同,不需要将数组重复元素删除,将重复元素后移返回对应长度即可。

2.思考二:可以调用Unique方法,但本质还是上述思想,将非重复元素前移。

1
2
3
4
5
6
7
8
class Solution {
public:
int removeDuplicates(vector<int>& nums) {
int n = nums.size();
auto pos = unique(nums.begin(),nums.end());
return distance(nums.begin(),pos);
}
};

27移除元素

image-20240309095109888

我的算法思想:双指针法(头尾指针):

从头尾同时遍历数组,根据题目要求,数组前半部分元素 != val值,后半部分 == val值,故当头指针指向元素的值 == val,与尾指针对应元素交换,尾指针前移;当不等时,头指针后移。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int n = nums.size();
if(n == 1 && nums[0] == val)
{
return 0;
}
int i = 0,j = n - 1;
while(i <= j)
{
if(nums[i] == val)
{
nums[i] = nums[j--];
}
else
{
i++;
}
}
return j + 1;
}
};

改进:头指针的值等于结果数组的长度;将尾指针初始位置后移一位,不用再单独判断n = 1的情况,同时while截至条件不需要等于。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int n = nums.size();
int i = 0,j = n;
while(i < j)
{
if(nums[i] == val)
{
nums[i] = nums[j-1];
j--;
}
else
{
i++;
}
}
return i;
}
};
思想二:双指针法(头头指针)

设置两个头指针,只要保证结果数组中左半部分的正确性即可,故令两个指针速度不同,慢指针指向左半数组应当填充元素位置,快指针用于遍历整个数组,当快指针指向元素 != val,将其加入慢指针指向位置,同时快慢指针后移;否则快指针后移。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int n = nums.size();
int slow = 0;
for(int fast = 0;fast < n;fast++)
{
if(nums[fast] != val)
{
nums[slow++] = nums[fast];
}
}
return slow;
}
};

35搜索插入位置

image-20240319112848606

我的算法思想:二分查找

由于题目要求时间复杂度必须为O(log n),所以首先想到二分查找的方法,如果找到目标值就返回mid索引,未找到目标值代表最终结果时low > high;只有两种情况:

1.nums[mid] > target:high前移,low指向应该插入位置

2.nums[mid] < target:low后移,low指向应该插入位置

其中low永远指向第一个小于target的后一元素

image-20240319114339183

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
int low = 0;
int high = nums.size()-1;
int mid = 0;
while(low <= high){
mid = (low+high)/2;
if(nums[mid] == target)
{
return mid;
}
else if(nums[mid] > target)
{
high = mid - 1;
}
else{
low = mid + 1;
}
}
return low;
}
};
采用移位计算mid防止溢出
1
int mid = ((right - left) >> 1) + left;
思想二:递归

66.加一

image-20240320112513928

我的思想:

从最后一位开始判断是否是9,如果是9,需要化0然后进位;否则加1返回数组即可;同时需要注意如果直到第一位也需要进位需要扩大数组长度;

采用递归

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Solution {
public:
vector<int> Binary(vector<int>& digits,int index){
if(digits[index] == 9)
{
digits[index] = 0;
if(index == 0)
{
digits.insert(digits.begin(),1);
}
else
{
Binary(digits,index - 1);
}
}
else{
digits[index] += 1;
return digits;
}
return digits;
}
vector<int> plusOne(vector<int>& digits) {
int n = digits.size();
return Binary(digits,n-1);
}
};
改进:直接遍历判断即可
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution {
public:
vector<int> plusOne(vector<int>& digits) {
int n = digits.size();
for(int i = n - 1;i>=0;i--)
{
if(++digits[i] < 10){
return digits;
}
else{
digits[i] = 0;
if(digits[0] == 0){
digits.insert(digits.begin(),1);
}
}
}
return digits;
}
};

再提速:循环内只判断是否等于9,如果可以从循环退出,意味第一位需要进位。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Solution {
public:
vector<int> plusOne(vector<int>& digits) {
int n = digits.size();
for(int i = n - 1;i>=0;i--)
{
if(++digits[i] < 10){
return digits;
}
else{
digits[i] = 0;
}
}
digits.insert(digits.begin(),1);
return digits;
}
};

88.合并两个有序数组

image-20240321110052483

我的思想:双指针

分别从头遍历两个数组,按照输入案例,需要保证有序性,即相等元素nums1在前;同时由于vector特性,需要特殊处理空数组情况

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Solution {
public:
void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
int i=0,j=0;
if(m + n == n){
nums1 = nums2;
}
while(i<m && j<n){
if(nums1[i]<=nums2[j])
i++;
else{
nums1.insert(nums1.begin()+i,nums2[j]);
nums1.pop_back();
m++;
j++;
}
}
while(j<n){
nums1[i++] = nums2[j++];
}

}
};

需要注意插入到nums1中的元素不能覆盖原有元素;

双指针改进:逆双指针

由于nums1数组后n位都是0,故可以从后遍历,每次选取较大的值放入;

内置函数法:

1.先将两个数组合并,再sort

2.直接merge(merge要求两个待合并排序的数组排序规则相同)

1
2
//将[first,first+len1)和[second,second+len2)默认升序合并到result
merge(first.begin(),first.begin()+len1,second.begin(),second.begin()+len2,result.begin());

网络安全复习

计算机网络安全,也称“网络安全”,是指计算机网络中的硬件资源和信息资源的安全性,它通过网络信息的产生、存储、传输和使用过程来体现,包括网络设备的安全性和网络信息的安全性。其是否安全通过可用性、保密性、完整性、不可抵赖性、可控制性来评估

阅读全文 »

复杂性理论复习综述

理论计算机的核心目标:

把计算任务按照其本质难度进行分类 ![image-20230626150513090](https://qitiantaile.oss-cn-guangzhou.aliyuncs.com/blog/image-20230626150513090.png) 复习重点:判定问题;图灵机构造和基本思想;什么是P、NP、NPC问题及NP问题之间的规约和常见的NPC问题;SAT、2SAT、3SAT问题;递归算法和非递归算法特点和区别;复杂度分析方法区别;会写素数判定的递归和非递归算法
阅读全文 »