41. 缺失的第一个正数
给你一个未排序的整数数组,请你找出其中没有出现的最小的正整数。
输入: [1,2,0]
输出: 3
提示:
你的算法的时间复杂度应为O(n),并且只能使用常数级别的额外空间。
算法描述
将所有的数 存入set去重 然后从1开始枚举所有正整数 不存在就输出
哈希(空间不满足要求)
class Solution {
public:
int firstMissingPositive(vector<int>& nums) {
unordered_set<int> hash;
for(auto& n:nums) hash.insert(n);
int res=1;
while(hash.count(res)) res++;
return res;
}
};
算法描述
先排序,然后找到第一个大于0的数,然后开始枚举
二分(时间不满足要求)
class Solution {
public:
int firstMissingPositive(vector<int>& nums) {
if(nums.size()==0) return 1;
sort(nums.begin(),nums.end());
int n=nums.size();
int l=0,r=n-1;
while(l<r){
int mid=l+r>>1;
if(nums[mid]>0) r=mid;
else l=mid+1;
}
int j=1;
for(int i=l;i<n;i++){
if(i && nums[i]==nums[i-1]) continue;
else{
if(nums[i]!=j) return j;
j++;
}
}
return j;
}
};
算法描述
数组n个元素 去掉非正数 最多是1-n 那么我们相当于自定义哈希函数将这些数映射到数组的0-n的位置 然后枚举所有元素 找到不匹配的位置就好了
算法流程
1 枚举所有的元素 对于正数n将它映射到数组n-1的位置 然后对于交换过来的元素 如果还是正数 继续操作 否则下一个元素 同时防止重复元素使得无限循环
2 枚举所有数 看看是否满足我们的哈希函数 不满足就输出
原地哈希
class Solution {
public:
int firstMissingPositive(vector<int>& nums) {
int n=nums.size();
for(int i=0;i<n;i++){
while(nums[i]>=1 && nums[i]<n && nums[nums[i]-1]!=nums[i])
swap(nums[nums[i]-1],nums[i]);
}
for(int i=0;i<n;i++)
if(nums[i]!=i+1) return i+1;
return n+1;
}
};
42. 接雨水
给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
输入:height = [0,1,0,2,1,0,1,3,2,1,2,1]
输出:6
解释:上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。
n == height.length
0 <= n <= 3 * 104
0 <= height[i] <= 105
算法描述
两边高中间低才能形成接水的凹槽 就比较容易找到单调栈的影子但是不同于单调栈的主流应用(找到第一个大于或者等于当前元素的数) 我们维持一个单调递减的序列 当新进来的元素高度大于栈顶元素的时候 因为当前元素高于栈顶元素 栈顶元素前面一个元素也大于栈顶元素(单调递减的序列) 所以形成了接水的凹槽 矩形的高度就是当前元素的高度和栈顶元素前一个元素的较小者和栈顶元素的差值 宽度就是当前元素和栈顶元素上一个元素之间的距离
然后栈顶元素出栈 算法继续 直到栈顶元素都大于等于当前元素了 当前元素对res的贡献计算完毕
单调栈
class Solution {
public:
int trap(vector<int>& height) {
stack<int> stk;
int res=0;
for(int i=0;i<height.size();i++){
while(stk.size() && height[i]>height[stk.top()]){
int cur=stk.top();
stk.pop();
if(stk.empty()) break;
int left=stk.top();
int right=i;
int h=min(height[left],height[right])-height[cur];
res+=h*(right-left-1);
}
stk.push(i);
}
return res;
}
};
43. 字符串相乘
给定两个以字符串形式表示的非负整数 num1 和 num2,返回 num1 和 num2 的乘积,它们的乘积也表示为字符串形式。
输入: num1 = “2”, num2 = “3”
输出: “6”
输入: num1 = “123”, num2 = “456”
输出: “56088”
算法描述
模拟一个列竖式的过程就好了 但是我们可以对列竖式的过程进行一下精简 使得我们编程更为舒适
就是先不考虑进位 然后计算出来的结果每一位上的数字可能是两位数 统一再来进位一次就好了
class Solution {
public:
string multiply(string num1, string num2) {
int n=num1.size(),m=num2.size();
vector<int> a,b;
//高精度的常态 倒着存
for(int i=n-1;i>=0;i--) a.push_back(num1[i]-'0');
for(int i=m-1;i>=0;i--) b.push_back(num2[i]-'0');
//模拟列竖式的过程 但是不进位呦
vector<int> c(n+m);
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
{
c[i+j]+=a[i]*b[j];
}
//统一进位
for(int i=0,t=0;i<n+m;i++)
{
t+=c[i];
c[i]=t%10;
t/=10;
}
//去掉前导0
int k=c.size()-1;
while(k>0 && c[k]==0) k--;
//结果倒序输出
string res;
while(k>=0) res+=c[k--]+'0';
return res;
}
};