LeetCode刷题1-数组-简单难度
前言
为了准备考研复试以及提高自己的代码能力,我准备到复试之前尽量多刷些算法题目,主要以简单和中等为主。每刷完一个标签的一个难度的题目就写博客汇总一下,目的主要是为了强迫自己去复习,提高熟练度。
LeetCode 1 两数之和
题目大意
给定一个整数数组 nums 和一个整数目标值 target ,在数组中找出和为 target 的那两个整数,并返回它们的数组下标。
注意:每种输入只会对应一个答案。但是,数组中同一个元素不能使用两遍。
思路
由于给出的示例不保证数组有序,因此不应该优先考虑二分法,二分的话首先需要对数组进行排序,至少 O(NlogN)。
这里可以考虑使用哈希表,以 {nums[i],i} 的形式存储。可以使用两遍循环,第一遍建立好哈希表,第二遍针对数组中的每个数,寻找在哈希表中是否有与其匹配的数。或者优化的方法是,只使用一次遍历,先判断已经建立的哈希表中是否有符合题意的数,如果没有,就将当前遍历到的数字存入表中。
时间复杂度:O(N),一次遍历即可
空间复杂度:O(N),主要是哈希表的开销
代码
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int,int> m;
for(int i=0;i<nums.size();i++){
if(m.find(target-nums[i])!=m.end()){
return {m[target-nums[i]],i};
//当前找到的匹配的数字的下标一定在前面
}
m[nums[i]]=i;
}
return {};
}
};
LeetCode 26 删除排序数组中的重复项
题目大意
给定一个排序数组,你需要在 原地 删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。
不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。
不需要考虑数组中超出新长度后面的元素。
思路
这里比较关键的是理解不需要考虑数组中超出新长度后面的元素
这个提示。那么我们可以直接对数组进行一次遍历,把每一个不重复的数字移到前面。可以设定一组双指针,指针i指向当前最后一个不重复的数字放置的位置,指针j指向原数组中下一个需要判断是否重复的数字。将两个指针所指数字比较,如果不同,则将指针j所指数字放到指针i所指位置的下一个。由于指针i为数组下标,所以最终返回时还需加1,才是不重复数字的个数。如果原始数组为空,则直接返回0。
时间复杂度:O(N),一次遍历即可
空间复杂度:O(1)
代码
class Solution {
public:
int removeDuplicates(vector<int>& nums) {
int n=0;
for(int i=1;i<nums.size();i++){
if(nums[i]!=nums[n]){
nums[++n]=nums[i];
}
}
return nums.size()==0?0:++n;
}
};
LeetCode 27 移除元素
题目大意
给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。
不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
思路
由于小于数组新长度的数字可以为任意顺序,那么在一次遍历中,我们可以将所有需要移除的数字和数组末端的数字进行交换。利用双指针i和j,指针i指向当前需要与val进行比较的数字,指针j指向数组末端可以用于交换的数字,如果指针i指的数字为val,则进行交换。注意,交换过后,i不能自增,还需要将交换过来的数字再和val比较,因为数组后端也可能有和val值相同的数字。
时间复杂度:O(N),一次遍历即可
空间复杂度:O(1)
代码
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int j=nums.size()-1;
int i=0;
while(i<=j)
if(nums[i]==val){
nums[i]=nums[j--];
}
else{
i++;
}
return ++j;
}
};
LeetCode 35 搜索插入位置
题目大意
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
思路
当看到有序数组时,不要再想着O(N)的遍历方法了,优先考虑二分法。需要注意,本题还可能找不到目标值,因此,要找到大于等于目标值的最大值的位置,即为插入位置。
时间复杂度:O(NlogN)
空间复杂度:O(1)
代码
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
int low=0,high=nums.size()-1;
while(low<=high){
int mid=(low+high)/2;
if(target>nums[mid]) low=mid+1;
else high=mid-1;
}
return low;
}
};
LeetCode 53 最大子序和
题目大意
给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
思路
这种题如果没有遇到过确实会一脸懵逼,不过做的多了也就没那么难了。简单的动态规划题目。对于数组中的每个位置i,我们都可以找到以这个位置为结尾的子数组的最大值max_sum[i],而整道题目的最大值也就是所有这些最大值中的最大值,即max(max_sum[i],i=0,1,2…)。而位置i为结尾的子数组的最大值为max(nums[i],nums[i]+max_sum[i-1]),这就是本题的DP转移方程。
时间复杂度:O(N)
空间复杂度:O(1)
代码
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int maxValue=nums[0];
for(int i=1;i<nums.size();i++){
nums[i]=max(nums[i-1]+nums[i],nums[i]);
maxValue=max(maxValue,nums[i]);
}
return maxValue;
}
};
本题还有O(NlogN)的方法,即类似线段树的递归方法,官方题解也已给出。