目录
十八**、小红的子串(字符种类在L到R之间的子串个数)(滑动窗口+前缀和)
一、旋转字符串(暴力/规律)

暴力:
class Solution {
public:
bool solve(string A, string B) {
if(A.length()!=B.length())return false;
int n=A.length();
for(int i=0;i<A.size();++i)
{
if(A[i]==B[0])
{
int tail=(i-1+n)%n,curA=i,curB=0;
while(curA!=tail)
{
if(A[curA]!=B[curB])break;
curA=(curA+1)%n;
++curB;
}
if(curA==tail)return true;
}
}
return false;
}
};
二、合并k个已排序的链表(归并/优先级队列+自定义排序)

看到算法复杂度nlogn就该想到归并排序
归并排序:
/**
* struct ListNode {
* int val;
* struct ListNode *next;
* ListNode(int x) : val(x), next(nullptr) {}
* };
*/
#include <vector>
class Solution {
public:
ListNode* mergeKLists(vector<ListNode*>& lists) {
int n=lists.size();
if(n==0)return nullptr;
return My_merge(lists,0,n-1);
}
ListNode* My_merge(vector<ListNode*>&lists,int left,int right)
{
if(left==right)return lists[left];
int mid=left+(right-left)/2;
ListNode*l1=My_merge(lists,left,mid);
ListNode*l2=My_merge(lists,mid+1,right);
return MergeTwoList(l1,l2);
}
ListNode* MergeTwoList(ListNode*l1,ListNode*l2)
{
if(l1==nullptr)return l2;
if(l2==nullptr)return l1;
ListNode*cur1=l1,*cur2=l2,*newhead=new ListNode(-1),*tail=newhead;
while(cur1&&cur2)
{
if(cur1->val<cur2->val)
{
tail->next=cur1;
cur1=cur1->next;
}
else {
tail->next=cur2;
cur2=cur2->next;
}
tail=tail->next;
}
while(cur1)
{
tail->next=cur1;
tail=tail->next;
cur1=cur1->next;
}
while(cur2)
{
tail->next=cur2;
tail=tail->next;
cur2=cur2->next;
}
tail=newhead->next;
delete newhead;
return tail;
}
};
优先级队列+自定义排序:
注意开始入堆的时候要判断是不是有空数组,否则段溢出
/**
* struct ListNode {
* int val;
* struct ListNode *next;
* ListNode(int x) : val(x), next(nullptr) {}
* };
*/
#include <queue>
class Solution {
public:
struct cmp
{
bool operator()(const ListNode*l1,const ListNode*l2)
{
return l1->val > l2->val;
}
};
ListNode* mergeKLists(vector<ListNode*>& lists) {
if(lists.empty())return nullptr;
priority_queue<ListNode*,vector<ListNode*>,cmp> hp;
for(auto&l:lists)
{
//这里需要判断一下
if(l)hp.push(l);
}
ListNode*newhead=new ListNode(-1),*tail=newhead;
while(!hp.empty())
{
ListNode* hp_top=hp.top();
hp.pop();
tail->next=hp_top;
tail=tail->next;
if(hp_top->next)hp.push(hp_top->next);
}
tail->next=nullptr;
tail=newhead->next;
delete newhead;
return tail;
}
};
三、滑雪(bfs)


这里地图长宽都是小于100的,如果数据量来到1000,使用dfs会因为递归深度过大导致爆栈,报错显示为段溢出,因此地图题还是使用bfs为妙。
#include <iostream>
#include<queue>
using namespace std;
const int N=101;
using PII=pair<int,int>;
int dx[4]={-1,1,0,0},dy[4]={0,0,-1,1},n,m,grid[N][N];
int bfs(int i,int j)
{
queue<PII> q;
q.push({i,j});
int step=0;
while(!q.empty())
{
++step;
int sz=q.size();
while(sz--)
{
auto [i,j]=q.front();
q.pop();
for(int k=0;k<4;++k)
{
int x=i+dx[k],y=j+dy[k];
if(x>=0&&x<n&&y>=0&&y<m&&grid[x][y]>grid[i][j])
q.push({x,y});
}
}
}
return step;
}
int main() {
cin>>n>>m;
for(int i=0;i<n;++i)
{
for(int j=0;j<m;++j)cin>>grid[i][j];
}
int len=1;
for(int i=0;i<n;++i)
{
for(int j=0;j<m;++j)len=max(len,bfs(i,j));
}
cout<<len;
return 0;
}
四、天使果冻(递推)


#include <climits>
#include <iostream>
using namespace std;
const int N=1e5+10;
int n,q,x,ans[N],max_num,max_next_num;
int main() {
cin>>n;
cin>> max_num;
for(int i=1;i<n;++i)
{
cin>>x;
if(x>=max_num)
{
max_next_num=max_num;
max_num=x;
}
else if(x>max_next_num)
{
max_next_num=x;
}
ans[i+1]=max_next_num;
}
cin>>q;
while(q--)
{
cin>>x;
cout<<ans[x]<<endl;
}
return 0;
}
五、dd爱旋转(模拟+利用规律优化)


#include <iostream>
#include <vector>
#include<algorithm>
using namespace std;
int n,q,x;
void Print(vector<vector<int>> arr)
{
for(int i=0;i<n;++i)
{
for(int j=0;j<n-1;++j)cout<<arr[i][j]<<" ";
cout<<arr[i][n-1]<<endl;
}
}
void Function_1(vector<vector<int>>& arr)
{
for(int i=0;i<n;++i)
{
reverse(arr[i].begin(),arr[i].end());
}
reverse(arr.begin(),arr.end());
}
void Function_2(vector<vector<int>>& arr)
{
reverse(arr.begin(),arr.end());
}
int main() {
cin>>n;
vector<vector<int>> arr(n,vector<int>(n));
for(int i=0;i<n;++i)
for(int j=0;j<n;++j)
cin>>arr[i][j];
cin>>q;
int count_1=0,count_2=0;
while(q--)
{
cin>>x;
if(x==1)++count_1;
else ++count_2;
}
if(count_1)
{
count_1%=2;
if(count_1)Function_1(arr);
}
if(count_2)
{
count_2%=2;
if(count_2)Function_2(arr);
}
Print(arr);
return 0;
}
六**、小红取数(01背包+同余定理)

最先使用dp而后以失败告终,随后
同余的记忆浮现于脑海,但是做法已经遗忘在了风中。。。
然后利用暴力的思路写了dfs,但是递归深度过大导致WA
#include <iostream>
#include <cstring>
using namespace std;
typedef long long LL;
const int N=1010;
LL arr[N];
LL dp[N][N];//dp[i][j]表示从前i个人选 总和%k==j时的最大和是多少
int n,k;
int main() {
cin>>n>>k;
memset(dp, -0x3f3f3f3f, sizeof dp);
dp[0][0] = 0;
for(int i=1;i<=n;++i) cin>>arr[i];
for(int i=1;i<=n;++i)
for(int j=0;j<k;++j)
dp[i][j]=max(dp[i-1][j],dp[i-1][(j-arr[i]%k+k)%k]+arr[i]);
if(dp[n][0]<=0) cout<<-1<<endl;
else cout<<dp[n][0]<<endl;
}
七、神奇的字母II(哈希)


#include<iostream>
#include<string>
using namespace std;
string s;
int main(){
int hash[26]={0};
char ret=0;
int maxcount=0;
while(cin>>s)
for(auto&ch:s)
if(++hash[ch-'a']>maxcount){
maxcount=hash[ch-'a'];
ret=ch;
}
cout<<ret<<endl;
}
八、字符编码(哈夫曼编码)

由于不了解哈夫曼编码遂通过率0,其实还是很简单的

#include <iostream>
#include <queue>
#include <string>
#include <vector>
using namespace std;
string s;
int main() {
while(cin>>s){
//先统计每个字符的频次 然后再丢到小根堆里
int hash[128]={0};
for(auto&ch:s) ++hash[ch];
//将频次丢到小根堆里
priority_queue<int,vector<int>,greater<int>> heap;
for(int i=0;i<128;++i)
if(hash[i]) heap.push(hash[i]);
int ret=0;
while(heap.size()>1){
int t1=heap.top();
heap.pop();
int t2=heap.top();
heap.pop();
ret+=t1+t2;
heap.push(t1+t2);
}
cout<<ret<<endl;
}
}
九*、最少的完全平方数(完全背包)

居然是完全背包问题,我还以为是贪心
中了贪心的陷阱
比如12这个数:用贪心来解,就是9+1+1+1 也就是4次
正确答案应该是4+4+4 3次!

#include <iostream>
#include <vector>
#include <algorithm>
#include <climits>
using namespace std;
int main() {
int n;
cin >> n;
vector<int> dp(n + 1, INT_MAX);
dp[0] = 0;
for (int i = 1; i <= n; i++) {
for (int j = 1; j * j <= i; j++) {
dp[i] = min(dp[i], dp[i - j * j] + 1);
}
}
cout << dp[n] << endl;
return 0;
}
最少完全平方数避免贪心策略

十**、游游的字母串(优化枚举)

666一直以为纯暴力会超时所以没写,亏大发
#include<iostream>
#include<string>
#include<cmath>
using namespace std;
string s;
int main(){
cin>>s;
int ret=0x3f3f3f3f;
for(char i='a';i<='z';++i){
int sum=0;//统计变化的次数
for(auto&ch:s)
sum+=min(abs(ch-i),26-abs(ch-i));
ret=min(sum,ret);
}
cout<<ret<<endl;
}
十一、体育课测试II (BFS拓扑排序)

#include <unordered_map>
class Solution {
public:
vector<int> findOrder(int numProject, vector<vector<int> >& groups) {
vector<int> in(numProject);
unordered_map<int, vector<int>> edages;
for(auto &arr:groups)
{
//b->a
int a=arr[0],b=arr[1];
++in[a];
edages[b].push_back(a);
}
queue<int> q;
for(int i=0;i<numProject;++i)
{
if(in[i]==0)q.push(i);
}
vector<int> ret;
while(!q.empty())
{
int sz=q.size();
while(sz--)
{
int b=q.front();
q.pop();
ret.push_back(b);
for(auto&a:edages[b])
{
if(--in[a]==0)q.push(a);
}
}
}
for(int i=0;i<numProject;++i)
{
if(in[i])return {};
}
return ret;
}
};
十二*、合唱队形(序列dp)

正着思考没思路,睡了一觉刷牙的时候突然想这不就是求最长的山峰序列的长度么。
然后又想到可以正反都弄一个dp表,每个位置的最长山峰序列就是两个dp[i]的值相加减去1.
但是最后一直通过百分之七十,因为笔试的时候看不到用例,做完后,我又找到了原题
173 132 142 161
预期输出1 ,结果输出了2,结果发现
初始化问题

应该是n+1,我#¥%¥%¥……%……¥*
#include <iostream>
#include<vector>
using namespace std;
const int N=1010;
int arr[N],n;
void Print(vector<int> arr)
{
for(int i=1;i<n;++i)cout<<arr[i]<<" ";
cout<<arr[n]<<endl;
}
int main() {
cin>>n;
for(int i=1;i<=n;++i)cin>>arr[i];
//n+1!!!因为要用到n
vector<int> f(n+1,1);
auto g=f;
//f[N]表示正序递增到i位置最长递增子序列的长度
for(int i=2;i<=n;++i)
{
for(int j=1;j<i;++j)
{
if(arr[j]<arr[i])
{
f[i]=max(f[i],f[j]+1);
}
}
}
//g[N]表示逆序递增到i位置最长递增子序列的长度
for(int i=n-1;i>=1;--i)
{
for(int j=n;j>i;--j)
{
if(arr[j]<arr[i])
{
g[i]=max(g[i],g[j]+1);
}
}
}
// Print(f);
// Print(g);
//计算最长“山峰”序列的长度
int len=1;
for(int i=1;i<=n;++i)
{
len=max(len,g[i]+f[i]-1);
}
cout<<n-len;
return 0;
}
十三、棋子翻转(模拟)

最简单的一题
class Solution {
public:
int dx[4]={-1,1,0,0},dy[4]={0,0,-1,1};
void change(int &x)
{
if(x==1)x=0;
else x=1;
}
vector<vector<int> > flipChess(vector<vector<int> >& A, vector<vector<int> >& f) {
int m=A.size();
for(int i=0;i<f.size();++i)
{
//处理映射
int x=f[i][0]-1,y=f[i][1]-1;
for(int k=0;k<4;++k)
{
int nx=x+dx[k],ny=y+dy[k];
if(nx>=0&&nx<m&&ny>=0&&ny<m)
{
change(A[nx][ny]);
}
}
}
return A;
}
};
十四**、宵暗的妖怪(区间dp)


dp题让我有点崩溃。。。。

//打家劫舍问题 但是不能抢到最后一家
#include<iostream>
using namespace std;
typedef long long LL;
const int N=1e5+10;
LL arr[N],dp[N];
//dp[i]表示1-i区间的最大饱食度是多少
//dp[i-3]+arr[i]
int n;
int main(){
cin>>n;
for(int i=1;i<=n;++i) cin>>arr[i];
for(int i=3;i<=n;++i)
dp[i]=max(dp[i-1],dp[i-3]+arr[i-1]);
cout<<dp[n]<<endl;
}
十五**、过桥(贪心+BFS+双指针优化掉队列)




#include<iostream>
using namespace std;
const int N=2010;
int arr[N],n;
int bfs(int arr[])
{
int ret=0,left=1,right=1;
while(left<=right)
{
++ret;
int l=left,r=right;
for(int i=left;i<=right;++i)
{
r=max(r,arr[i]+i);
if(r>=n)return ret;
}
left=right+1;
right=r;
}
return -1;
}
int main()
{
cin>>n;
for(int i=1;i<=n;++i)cin>>arr[i];
cout<<bfs(arr);
return 0;
}
十六、最大差值

思路一:暴力->超时
思路二:用两个数组,一个数组存0~i位置最小值,一个数组存i~n-1位置的最大值,然后遍历记录最大差值(可行,还可以优化)
#include <climits>
#include <vector>
class Solution {
public:
int getDis(vector<int>& A, int n) {
vector<int> MinNum(n+1),MaxNum(n+1);
MinNum[0]=INT_MAX;
MaxNum[n]=INT_MIN;
for(int i=1;i<=n;++i)MinNum[i]=min(MinNum[i-1],A[i-1]);
for(int i=n-1;i>=0;--i)MaxNum[i]=max(MaxNum[i+1],A[i]);
//MinNum: 1~n MaxNum: 0~n-1 A: 0~n-1
int ret=0;
for(int i=0;i<n;++i)
{
ret=max(ret,MaxNum[i]-MinNum[i+1]);
}
return ret;
}
};
思路三:从前往后遍历,用一个变量存储遍历到i位置的最小值,这样往后每个位置只需贪心减去该数即可,不用0~i区间都试一次
class Solution {
public:
int getDis(vector<int>& A, int n) {
int ret=0;//记录最大差值
int prevmin=A[0];//记录在这之前的最小值
for(int i=1;i<n;++i){
ret=max(ret,A[i]-prevmin);
prevmin=min(prevmin,A[i]);
}
return ret;
}
};
十七**、兑换零钱(完全背包)



可进一步优化为一维数组
#include <iostream>
#include <cstring>
using namespace std;
//dp[i][j]表示从前i个数选 面值恰好为j的最小张数
const int N=1010,M=5010;
int n,aim;
int arr[N],dp[M];
int main() {
cin>>n>>aim;
memset(dp,0x3f,sizeof dp);
dp[0]=0;
for(int i=1;i<=n;++i) cin>>arr[i];
for(int i=1;i<=n;++i)
for(int j=arr[i];j<=aim;++j)
dp[j]=min(dp[j],dp[j-arr[i]]+1);
if(dp[aim]>=0x3f3f3f3f) cout<<-1<<endl;
else cout<<dp[aim]<<endl;
}
十八**、小红的子串(字符种类在L到R之间的子串个数)(滑动窗口+前缀和)


很明显是滑动窗口题
如果L==1,那就是纯滑动窗口的思路

那么我们以1为开始,求出字符种类在[1,L-1]区间内的子串数量 再求出字符种类在 [1,R]区间内子串数量,再做差,就是字符种类在[L,R]区间内的子串数量

#include<iostream>
using namespace std;
int n,l,r;
string s;
long long find(int x)
{
long long ret=0;
//模拟哈希表
int hash[26]={0},kinds=0,left=0,right=0;
while(right<n)
{
if(hash[s[right]-'a']++ ==0)++kinds;
while(kinds>x)
{
if(--hash[s[left]-'a']==0)--kinds;
++left;
}
ret+=right-left+1;
++right;
}
return ret;
}
int main()
{
cin>>n>>l>>r>>s;
cout<<find(r)-find(l-1);
return 0;
}
本周笔试完结撒花/(ㄒoㄒ)/~~

7293

被折叠的 条评论
为什么被折叠?



