说明
- 我这里写个是为了做一下整理
- 我觉得有趣,如果开发累了,可以换一换脑子
- 注:题目可直抵题目,所以不写题目内容
题目讲解[哈希+双指针+滑动窗口+子串+普通数组+矩阵]
哈希:快速映射和快速查找
- 暴力法
暴力法就是遍历所有数,然后两两相加,如果和等于目标值,则返回结果,否则返回-1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
class Solution {
public:
vector<int> twoSum(std::vector<int>& nums, int target) {
int n = nums.size();
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
if (nums[i] + nums[j] == target) {
return {i, j};
}
}
}
return {};
}
};
|
- 哈希表
- 哈希表就是将数组中的数作为键,索引作为值,然后遍历数组,将每个数作为键,索引作为值,如果哈希表中存在目标值,则返回结果,否则返回-1
- 时间复杂度:O(n) 为什么可以优化时间呢?
因为哈希表的查找时间杂度是 O(1),而数组的查找时间复杂度是 O(n),所以哈希表可以提高查找效率。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
class Solution {
public:
vector<int> twoSum(std::vector<int>& nums, int target) {
int n = nums.size();
unordered_map<int,int>mp;
for(int i=0;i<n;i++){
if(mp.find(target-nums[i])!=mp.end()){
return {i,mp[target-nums[i]]};
}
mp[nums[i]]=i;
}
return {};
}
};
|
- 思路:哈希表,将字符串排序,作为键,将原字符串作为值,然后遍历字符串,将排序后的字符串作为键,将原字符串作为值,如果哈希表中存在目标值,则返回结果,否则返回-1
- 时间复杂度:O(n)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
class Solution {
public:
vector<vector<string>> groupAnagrams(vector<string>& strs) {
unordered_map<string,vector<string>>m;
for(string& s:strs){
string s1=s;
sort(s1.begin(),s1.end());
m[s1].push_back(s);
}
vector<vector<string>>ans;
ans.reserve(m.size());
for(auto & [x,value]:m){
ans.push_back(value);
}
return ans;
}
};
|
- 思路:因为是O(n)所以是不能用排序,所以要用不能用排序,要用unordered_set的特性
先来去重,然后在用.count() 去查找计数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
class Solution {
public:
int longestConsecutive(vector<int>& nums) {
unordered_set<int>st(nums.begin(),nums.end());
int ans=0;
for(int x:st){
if(!st.count(x-1)){
continue;
}
int now=x;
int cnt=1;
while(st.count(now+1)){
now++;
cnt++;
}
ans=max(ans,cnt);
}
return ans;
}
}
|
双指针
- 思路:双指针,一个指针指向当前位置,一个指针指向下一个位置,如果当前位置为0,则将下一个位置的值赋给当前位置,然后将下一个位置指针后移一位,直到下一个位置为0,然后将当前位置指针后移一位,直到数组末尾
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
class Solution {
public:
void moveZeroes(vector<int>& nums) {
int l=0,r=1;
if(nums.size()==1) return;
while(r<nums.size()){
if(nums[l]!=0){
l++;
}
if(nums[l]==0){
if(nums[r]!=0){
swap(nums[l],nums[r]);
l++;
}
}
r++;
}
}
};
|
- 思路:贪心+双指针
这题往双指针方向想很正常,问题在于怎么让矩形更大(x*y)
贪心在:面积 = min(左高, 右高) × (右索引 - 左索引)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
class Solution {
public:
int maxArea(vector<int>& height) {
int l=0,r=height.size()-1;
int ans=0;
while(l<r){
if(height[l]<height[r]){
ans=max(ans,height[l]*(r-l));
l++;
}
else{
ans=max(ans,height[r]*(r-l));
r--;
}
}
return ans;
}
};
|
- 思路:三个数和双指针,那怎么办?=>先排序后固定一个数(b + c = -a),O(n2)
重点:不能全局去重改变数组 。三个数都要做去重
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
|
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>>ans;
int n=nums.size();
sort(nums.begin(),nums.end());
for(int i=0;i<n;i++){
if(nums[i]>0) break;
if(i>0&&nums[i]==nums[i-1]) continue;
int l=i+1,r=n-1;
while(l<r){
int sum=nums[i]+nums[l]+nums[r];
if(sum==0){
ans.push_back({nums[i],nums[l],nums[r]});
while(l<r&&nums[l]==nums[l+1]) l++;
while(l<r&&nums[r]==nums[r-1]) r--;
l++,r--;
}
else if(sum>0) r--;
else l++;
}
}
return ans;
}
};
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
class Solution {
public:
int trap(vector<int>& height) {
int lmax=0,rmax=0;
int l=0,r=height.size()-1;
int n=height.size();
int ans=0;
while(l<r){
lmax=max(lmax,height[l]);
rmax=max(rmax,height[r]);
if(lmax>rmax) {
ans+=rmax-height[r];
r--;
}
else{
ans+=lmax-height[l];
l++;
}
}
return ans;
}
};
|
滑动窗口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
class Solution {
public:
int lengthOfLongestSubstring(string s) {
int l=0;
unordered_map<char,int>mp;
int ans=0;
for(int i=0;i<s.length();i++){
char c=s[i];
mp[c]++;
while(mp[c]>1){
mp[s[l]]--;
l++;
}
ans=max(ans,i-l+1);
}
return ans;
}
};
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
class Solution {
public:
vector<int> findAnagrams(string s, string p) {
sort(p.begin(), p.end());
vector<int> ans;
int len = p.size();
int n = s.size();
for (int l = 0; l + len <= n; l++) {
string res = s.substr(l, len);
sort(res.begin(), res.end());
if (res == p) {
ans.push_back(l);
}
}
return ans;
}
};
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
class Solution {
public:
vector<int> findAnagrams(string s, string p) {
vector<int> ans;
vector<int>cnt1(26,0);
vector<int>cnt2(26,0);
int len=p.size();
for(int i=0;i<p.size();i++){
cnt1[p[i]-'a']++;
}
for(int r=0;r<s.size();r++){
cnt2[s[r]-'a']++;
int l=r-len+1;
if(l<0) continue;
if(cnt1==cnt2) ans.push_back(l);
cnt2[s[l]-'a']--;
}
return ans;
}
};
|
子串
*思考过程:前缀和+哈希
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
class Solution {
public:
int subarraySum(vector<int>& nums, int k) {
int n=nums.size();
vector<int>sum(n+1);
for(int i=0;i<nums.size();i++){
sum[i+1]=sum[i]+nums[i];
}
int ans=0;
unordered_map<int,int>mp;
mp[0]=1;
for(int i=1;i<=n;i++){
if(mp.find(sum[i]-k)!=mp.end()) ans+=mp[sum[i]-k];
mp[sum[i]]++;
}
return ans;
}
};
|
*单调队列版子,没什么好说的
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
class Solution {
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
deque<int>q;
vector<int>ans;
for(int i=0;i<nums.size();i++){
while(!q.empty()&&nums[q.back()]<nums[i]) q.pop_back();
q.push_back(i);
if(i>=k-1)//窗口长度为k,因为是从0开始,所以i-k+1为窗口的起始位置
{
while(!q.empty()&&q.front()<=i-k) q.pop_front();
ans.push_back(nums[q.front()]);
}
}
return ans;
}
};
|
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
27
28
29
30
31
32
33
|
#include<bits/stdc++.h>
class Solution {
public:
string minWindow(string s, string t) {
int n=s.size();
int m=t.size();
unordered_map<char,int>cnt_n,cnt;
for(auto &x:t) cnt_n[x]++;
int l=0,r=0;
int need=0;
int mi=INT_MAX;
int st=0;
while(r<n){
char c=s[r++];
if(cnt_n.count(c)){
cnt[c]++;
if(cnt[c]==cnt_n[c]) need++;
}
while(need==cnt_n.size()){
if(r-l<mi){
st=l;
mi=r-l;
}
char d=s[l++];
if(cnt_n.count(d)){
if(cnt[d]==cnt_n[d]) need--;
cnt[d]--;
}
}
}
return mi==INT_MAX?"":s.substr(st,mi);
}
};
|
数组
1
2
3
4
5
6
7
8
9
10
11
|
class Solution {
public:
int maxSubArray(vector<int>& nums) {
vector<int>dp(nums.size());
dp[0]=nums[0];
for(int i=1;i<nums.size();i++){
dp[i]=max(nums[i],dp[i-1]+nums[i]);
}
return *max_element(dp.begin(),dp.end());
}
};
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
// (要维护的)
//num[0][1]>nums[1][0] 3>2
//nums[0][0]<nums[1][0] 1<2
//比较 nums[0][1] 和 nums[1][1]
class Solution {
public:
vector<vector<int>> merge(vector<vector<int>>& intervals) {
sort(intervals.begin(),intervals.end());
vector<vector<int>>ans;
for(auto & p:intervals){
if(!ans.empty()&&p[0]<=ans.back()[1]){
ans.back()[1]=max(ans.back()[1],p[1]);
}
else ans.push_back(p);
}
return ans;
}
};
|
1
2
3
4
5
6
7
8
9
10
|
class Solution {
public:
void rotate(vector<int>& nums, int k) {
int n=nums.size();
k=k%n;
reverse(nums.begin(),nums.end());
reverse(nums.begin(),nums.begin()+k);
reverse(nums.begin()+k,nums.end());
}
};
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
class Solution {
public:
vector<int> productExceptSelf(vector<int>& nums) {
int n=nums.size();
vector<int>pre(n,1);
vector<int>suf(n,1);
for(int i=1;i<n;i++){
pre[i]=pre[i-1]*nums[i-1];
}
for(int i=n-2;i>=0;i--){
suf[i]=suf[i+1]*nums[i+1];
}
vector<int>ans(n);
for(int i=0;i<n;i++){
ans[i]=pre[i]*suf[i];
}
return ans;
}
};
|
时间复杂度O(n),空间是O(n)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
class Solution {
public:
int firstMissingPositive(vector<int>& nums) {
unordered_set<int> s;
for (int num : nums) {
if (num >0&&num<=n) {
s.insert(num);
}
}
int res=1;
while(s.count(res)) res++;
return res;
}
};
|
仔细思考一下,最大可能是n+1,最小是1,可以假设是最大情况,最后发现第一个不符合题意的就是ans;
- for 跑 n 次,while 每次跑 n 次 → n×n = O (n²),这是不对的,实际上只会交换n次,时间复杂度是O(n)
这是并行次数,不是嵌套次数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
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[i],nums[nums[i]-1]);
}
}
for(int i=0;i<n;i++){
if(nums[i]!=i+1) return i+1;
}
return n+1;
}
};
|
矩阵
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
class Solution {
public:
void setZeroes(vector<vector<int>>& matrix) {
int m=matrix.size();int n=matrix[0].size();
vector<bool>a(m);
vector<bool>b(n);
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
if(matrix[i][j]==0){
a[i]=b[j]=1;
}
}
}
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
if(a[i]==1||b[j]==1) matrix[i][j]=0;
}
}
}
};
|
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
27
28
29
30
31
32
33
34
35
36
37
38
|
class Solution {
public:
vector<int> spiralOrder(vector<vector<int>>& matrix) {
int l=0,r=matrix[0].size()-1;
int top=0,bottom=matrix.size()-1;
vector<int>ans;
while(1){
//左到右
for(int i=l;i<=r;i++){
ans.push_back(matrix[top][i]);
}
top++;
if(top>bottom) break;
//上到下
for(int i=top;i<=bottom;i++){
ans.push_back(matrix[i][r]);
}
r--;
if(l>r) break;
//右到左
for(int i=r;i>=l;i--){
ans.push_back(matrix[bottom][i]);
}
bottom--;
if(top>bottom) break;
//下到上
for(int i=bottom;i>=top;i--){
ans.push_back(matrix[i][l]);
}
l++;
if(l>r) break;
}
return ans;
}
};
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
class Solution {
public:
void rotate(vector<vector<int>>& matrix) {
int n=matrix.size();
for(int i=0;i<n;i++){
for(int j=0;j<i;j++){
if(i==j) continue;
swap(matrix[i][j],matrix[j][i]);
}
}
for(int i=0;i<n;i++){
reverse(matrix[i].begin(),matrix[i].end());
}
}
};
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
class Solution {
public:
bool searchMatrix(vector<vector<int>>& matrix, int target) {
int top=0;
int r=matrix[0].size()-1;
while(top<=matrix.size()-1&&r>=0){
if(matrix[top][r]==target){
return true;
}
else if(matrix[top][r]>target){
r--;
}
else if(matrix[top][r]<target){
top++;
}
}
return false;
}
};
|