刷题记录
比特
Brian Kernighan算法
删除二进制比特最右侧1;
f(x)=x&(x-1);
例:
7=111
6=110
f(7)=7&6=110
例:
52=110100
51=110011
f(52)=52&51=110000
排序
快速排序
//快速排序
void quick_sort(int s[], int l, int r)
{
if (l < r)
{
//Swap(s[l], s[(l + r) / 2]); //将中间的这个数和第一个数交换 参见注1
int i = l, j = r, x = s[l];
while (i < j)
{
while(i < j && s[j] >= x) // 从右向左找第一个小于x的数
j--;
if(i < j)
s[i++] = s[j];
while(i < j && s[i] < x) // 从左向右找第一个大于等于x的数
i++;
if(i < j)
s[j--] = s[i];
}
s[i] = x;
quick_sort(s, l, i - 1); // 递归调用
quick_sort(s, i + 1, r);
}
}
例题:数组中的第k大的数字
class Solution {
public:
int quick_sort(vector<int>& nums,int l, int r)
{
if(l<r)
{
int i=l,j=r,x=nums[l];
while(i<j)
{
while(i<j&&nums[j]>=x)
j--;
if(i<j)
nums[i++]=nums[j];
while(i<j&&nums[i]<x)
i++;
if(i<j)
nums[j--]=nums[i];
nums[i]=x;
}
return i;
}
return l;
}
int findKthLargest(vector<int>& nums, int k) {
int n=nums.size();
int l=0,r=n-1;
int target=n-k;
int index=quick_sort(nums,l,r);
while(index!=target)
{
if(index>target)
{
r=index-1;
}
else
{
l=index+1;
}
index=quick_sort(nums,l,r);
}
return nums[target];
}
};
归并排序
//归并排序
void Merge(int arr[],int l,int mid,int r)
{
int i=l,j=mid+1,k=0;
int temp[r-l+1];
while(i<=mid&&j<=r)
{
if(arr[i]<=arr[j])
temp[k++]=arr[i++];
else
temp[k++]=arr[j++];
}
while(i<=mid)
temp[k++]=arr[i++];
while(j<=r)
temp[k++]=arr[j++];
for(i=l,k=0;i<=r;i++,k++)
arr[i]=temp[k];
}
void MergeSort(int arr[],int l,int r)
{
if(l<r)
{
int mid=(l+r)/2;
MergeSort(arr,l,mid);
MergeSort(arr,mid+1,r);
Merge(arr,l,mid,r);
}
}
广度优先搜索
三国鼎立
//C++
#include<iostream>
#include<string>
#include<vector>
using namespace std;
void dfs(vector<vector<int>> &area,int i,int j,int k)
{
int n=area.size();
int m=area[0].size();
area[i][j]=0;
if(i-1>=0&&area[i-1][j]==k)
dfs(area,i-1,j,k);
if(i+1<n&&area[i+1][j]==k)
dfs(area,i+1,j,k);
if(j-1>=0&&area[i][j-1]==k)
dfs(area,i,j-1,k);
if(j+1<m&&area[i][j+1]==k)
dfs(area,i,j+1,k);
}
int main()
{
int n,m;
cin>>n>>m;
vector<vector<int>> area(n,vector<int> (m));
int count=0;
for(int i=0;i<n;i++)
{
string s;
cin>>s;
for(int j=0;j<m;j++)
{
area[i][j]=s[j]-'0';
}
}
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
if(area[i][j]!=0)
{
count++;
dfs(area,i,j,area[i][j]);
}
}
}
cout<<count<<endl;
return 0;
}
集合优先队列
集合操作
#include<set>
begin() //返回set容器的第一个元素的地址
end() //返回set容器的最后一个元素地址
clear() //删除set容器中的所有的元素
empty() //判断set容器是否为空
max_size() //返回set容器可能包含的元素最大个数
size() //返回当前set容器中的元素个数
erase(it) //删除迭代器指针it处元素
insert(a) //插入某个元素
count(a) //统计元素a出现的次数,只有0/1,所以可以通过次函数返回判断某个元素是否在集合中
for(set<int>::iterator i=a.begin();i!=a.end();i++) //迭代器
优先队列
#inclued<queue>
priority_queue <int> q; //默认大顶堆
//升序队列,小顶堆
priority_queue <int,vector<int>,greater<int> > q;
//降序队列,大顶堆
priority_queue <int,vector<int>,less<int> >q;
top() //访问队头元素
empty() //队列是否为空
size() //返回队列内元素个数
push() //插入元素到队尾 (并排序)
emplace() //原地构造一个元素并插入队列
pop() //弹出队头元素
swap() //交换内容
狡猾的雇主
//使用两个集合解题
#include<iostream>
#include<vector>
#include<set>
#include<queue>
using namespace std;
int main()
{
int n;
cin>>n;
vector<int> salary(n);
priority_queue<int,vector<int>,greater<int> > q;
set<int> a,b;
for(int i=0;i<n;i++)
{
cin>>salary[i];
if(a.count(salary[i])==1)
b.insert(salary[i]);
a.insert(salary[i]);
}
for(set<int>::iterator i=a.begin();i!=a.end();i++)
{
if(b.count(*i)==0)
q.push(*i);
}
if(q.empty())
cout<<-1<<endl;
else{
int c=q.top();
cout<<c<<endl;
}
return 0;
}
并查集
初始化
//单独形成集合,每个节点的祖先为自己
int fa[size];
for(int i=0;i<size;i++)
fa[i]=i;
查找
int findfather(int fa[], int x)
{
if(fa[x]!=x) //如果自己的祖先不是自己,说明不是集合的祖先
fa[x]=findfather(fa,fa[x]); //查找集合的祖先,并进行压缩
return fa[x];
}
合并
bool unionn(int fa[],int i, int j)
{
int fa_i=findfa(fa,i);
int fa_j=findfa(fa,j);
if(fa_i!=fa_j)
{
fa[fa_i]=fa_j; //若两个节点祖先不同,不在同一个集合;则将其合并,其中一个祖先设为另一个的祖先,
return true; //刚建立集合,返回true
}
return false; //之前就存在集合,返回false
}
例题
剑指offer II 116 朋友圈
def findfather(fa,i):
if fa[i]!=i:
fa[i]=findfather(fa,fa[i])
return fa[i]
def union(fa,i,j):
fa_i=findfather(fa,i)
fa_j=findfather(fa,j)
if fa_i!=fa_j:
fa[i]=fa_j
return True
return False
if __name__=='__main__':
n=int(input())
M=[]
for i in range(n):
m=[int(j) for j in input().split(',')]
M.append(m)
fa=[-1]*n
for i in range(n):
fa[i]=i
count=n
for i in range(n):
for j in range(i+1,n):
if M[i][j]==1 and union(fa, i, j):
count-=1
print(count)
腾讯2021年校招 朋友圈
#include<iostream>
using namespace std;
int findfa(int fa[],int x)
{
if(fa[x]!=x)
fa[x]=findfa(fa,fa[x]);
return fa[x];
}
void unionn(int fa[],int x, int y)
{
int fa_x=findfa(fa,x);
int fa_y=findfa(fa,y);
if(fa_x!=fa_y)
fa[fa_x]=fa_y;
}
int main()
{
int T;
cin>>T;
while(T--)
{
int fa[100001];
int n;
cin>>n;
for(int i=0;i<100001;i++)
fa[i]=i;
while(n--)
{
int x,y;
cin>>x>>y;
unionn(fa,x,y);
}
vector<int> nums(100001);
int max_len=0;
for(int i=0;i<100001;i++)
{
int k=findfa(fa,i);
nums[k]++;
max_len=max(max_len,nums[k]);
}
cout<<max_len<<endl;
}
return 0;
}
剑指offer II 117 相似的字符串
class Solution {
public:
// 通过统计不同字符串的个数,判断是否相似
bool similarity(string s1, string s2)
{
int diff=0;
for(int i=0;i<s1.length();i++)
{
if(s1[i]!=s2[i])
diff++;
}
if(diff<=2)
return true;
else
return false;
}
//查找
int findfateher(int fa[],int i)
{
if(fa[i]!=i)
fa[i]=findfateher(fa,fa[i]);
return fa[i];
}
//合并
bool unionn(int fa[], int i, int j)
{
int fa_i=findfateher(fa,i);
int fa_j=findfateher(fa,j);
if(fa_i!=fa_j)
{
fa[fa_i]=fa_j;
return true;
}
return false;
}
int numSimilarGroups(vector<string>& strs) {
int n=strs.size();
int fa[n];
for(int i=0;i<n;i++)
{
fa[i]=i;
}
//初始化,每个字符串都是独立的,所以存在n个字符组
int nums=n;
for(int i=0;i<n;i++)
{
for(int j=i+1;j<n;j++)
{
//判断两个字符串是否相似,并且之前是否已经联通,字符组数量减一
if(similarity(strs[i],strs[j])&&unionn(fa,i,j))
{
nums--;
}
}
}
return nums;
}
};
剑指offer II 118 多余的边
class Solution {
public:
// 查找
int findfa(int fa[], int i)
{
if(fa[i]!=i)
fa[i]=findfa(fa,fa[i]);
return fa[i];
}
// 合并
bool unionn(int fa[],int i, int j)
{
int fa_i=findfa(fa,i);
int fa_j=findfa(fa,j);
if(fa_i!=fa_j)
{
fa[fa_i]=fa_j;
return true; //若之前不存在连接,则建立连接,返回true
}
return false; //之前存在连接,返回false
}
vector<int> findRedundantConnection(vector<vector<int>>& edges) {
int n=edges.size();
int maxleaf=0;
//查找最大节点的值
for(int i=0;i<n;i++)
{
maxleaf=max(maxleaf,edges[i][0]);
maxleaf=max(maxleaf,edges[i][1]);
}
int fa[maxleaf+1]; //此处记的加1,因为从1开始到n;
for(int i=0;i<maxleaf+1;i++)
{
fa[i]=i;
}
int i;
for(auto edge:edges)
{
if(!unionn(fa,edge[0],edge[1])) //判断是否形成环
return edge;
}
return vector<int> {
};
}
};
剑指offer II 119 最长连续序列
class Solution {
public:
int findfa(unordered_map<int,int>& fa, int i)
{
if(fa[i]!=i)
fa[i]=findfa(fa,fa[i]);
return fa[i];
}
void unionn(unordered_map<int,int>& fa, unordered_map<int,int>& count,int i, int j)
{
int fa_i=findfa(fa,i);
int fa_j=findfa(fa,j);
if(fa_i!=fa_j)
{
fa[fa_i]=fa_j;
count[fa_j]=count[fa_j]+count[fa_i];
}
}
int longestConsecutive(vector<int>& nums) {
unordered_map<int,int> fa;
unordered_map<int,int> count;
set<int> all;
for(int i=0;i<nums.size();i++)
{
fa[nums[i]]=nums[i];
count[nums[i]]=1;
all.insert(nums[i]);
}
for(int i=0;i<nums.size();i++)
{
if(all.count(nums[i]-1)==1)
{
unionn(fa,count,nums[i],nums[i]-1);
}
if(all.count(nums[i]+1)==1)
{
unionn(fa,count,nums[i],nums[i]+1);
}
}
int len=0;
for(int i=0;i<nums.size();i++)
{
len=max(len,count[nums[i]]);
}
return len;
}
};
单调栈
下一个更大元素
输入一个数组,返回等长数组,对应索引存储着下一个更大的元素,如果没有更大的元素,就存-1。
输入:nums=[ 2, 1, 2, 4, 3 ]
返回:[ 4, 2, 4, -1, -1 ]
## lubuladong的算法小抄——p267
vector<int> nextGreaterElement(vector<int>& nums)
{
vector<int> ans(nums.size());
stack<int> s;
for(int i=nums.size()-1;i>=0;i--) //倒序
{
while(!s.empty()&&s.top()<=nums[i])
{
s.pop(); //数值小的出栈;
}
ans[i]=s.empty()?-1:s.top(); //大于该元素的第一个数值;
s.push(nums[i]); //进栈
}
return ans;
}
剑指 Offer II 038. 每日温度
请根据每日 气温 列表 temperatures ,重新生成一个列表,要求其对应位置的输出为:要想观测到更高的气温,至少需要等待的天数。如果气温在这之后都不会升高,请在该位置用 0 来代替。
输入: temperatures = [73,74,75,71,69,72,76,73]
输出: [1,1,4,2,1,1,0,0]
class Solution {
public:
vector<int> dailyTemperatures(vector<int>& temperatures) {
int len=temperatures.size();
stack<int> s;
vector<int> ans(len);
for(int i=len-1;i>=0;i--)
{
while(!s.empty()&&temperatures[i]>=temperatures[s.top()])
{
s.pop();
}
ans[i]=s.empty()?0:s.top()-i;
s.push(i);
}
return ans;
}
};
柱状图中最大的矩形
class Solution {
public:
int largestRectangleArea(vector<int>& heights) {
int len=heights.size();
vector<int> left(len), right(len);
stack<int> s;
for(int i=0;i<len;i++)
{
while(!s.empty()&&heights[i]<=heights[s.top()])
s.pop();
left[i]=s.empty()?-1:s.top();
s.push(i);
}
s=stack<int> ();
for(int i=len-1;i>=0;i--)
{
while(!s.empty()&&heights[i]<=heights[s.top()])
s.pop();
right[i]=s.empty()?len:s.top();
s.push(i);
}
int max_m=0;
for(int i=0;i<len;i++)
{
max_m=max(max_m,(right[i]-left[i]-1)*heights[i]);
}
return max_m;
}
};
85. 最大矩形
class Solution {
public:
int largestRectangleArea(vector<int>& heights) {
int len=heights.size();
vector<int> left(len), right(len,len); //注意对right初始值赋len;
stack<int> s;
for(int i=0;i<len;i++)
{
while(!s.empty()&&heights[i]<=heights[s.top()])
{
right[s.top()]=i;
s.pop();
}
left[i]=s.empty()?-1:s.top();
s.push(i);
}
int max_m=0;
for(int i=0;i<len;i++)
{
max_m=max(max_m,(right[i]-left[i]-1)*heights[i]);
}
return max_m;
}
};
class Solution {
public:
int maximalRectangle(vector<vector<char>>& matrix) {
int row=matrix.size();
int col=matrix[0].size();
vector<vector<int>> height(row,vector<int>(col,0));
for(int i=0;i<row;i++)
for(int j=0;j<col;j++)
{
if(matrix[i][j]=='1')
height[i][j]=(i==0?1:height[i-1][j]+1);
}
vector<int> left(col,0),right(col,col);
stack<int> s;
int ans=0;
for(int i=0;i<row;i++)
{
for(int j=0;j<col;j++)
{
while(!s.empty()&&height[i][j]<s.top())
{
right[s.top()]=j;
s.pop();
}
left[j]=s.empty()?-1:s.top();
s.push(j);
}
s=stack<int> ();
for(int k=0;k<col;k++)
{
ans=max(ans,(right[k]-left[k]-1)*height[i][k]);
}
}
return ans;
}
};