腾讯《后台&综合-第一次笔试》题解
一共五道题,做不完,做了四道,有一道没时间了。
字符串压缩解压:
普通模拟,用栈存下来左括号,每次遇到一个右括号,就把中间的字符串分析一遍,解压
string s; struct p{ int l; int r; p(int a,int b){ l = a; r = b; } }; stack<int> kuo; int main(){ cin>>s; int n = s.size(); for(int i=0;i<n;++i){ if(s[i] == '['){ kuo.push(i); } if(s[i] == ']'){ int t = kuo.top(); kuo.pop(); string a = s.substr(t+1, i-t-1); bool flag = 0; int num = 0; string str; for(int j=0;j<a.size();++j){ if(!flag && isdigit(a[j])){ num+=a[j]-'0'; num*=10; } else if(a[j] == '|'){ flag = true; str = a.substr(j+1, n-j-1); break; } } num/=10; string replace; for(int j=0;j<num;++j){ replace += str; } s = s.substr(0,t)+ replace + s.substr(i+1, n-i-1); n = s.size(); i = t+replace.size()-1; } } cout<<s<<endl; }
放多少个xxx可以覆盖整条河面 最小区间覆盖问题
先按照左值排序,然后右值倒叙
struct p{ int l; int r; bool operator<(const p & a)const{ if(l == a.l) return r>a.r; return l<a.l; } } arg[100005]; int main(){ cin>>n>>l; for(int i=0;i<n;++i){ cin>>arg[i].l>>arg[i].r; } sort(arg, arg+n); if(arg[0].l>0){ cout<<-1<<endl; return 0; } int right = 0, pos = 0, max_len = 0; int ans=0; while(true){ if(right >= l){ break; } for(int i=pos;i<n;++i){ if(arg[i].l<=right && arg[i].r > max_len){ pos = i; max_len = arg[i].r; } if(arg[i].l>right){ break; } } if(max_len == right){ cout<<-1<<endl; return 0; } right = max_len; ++ans; } cout<<ans<<endl; }
反转区间之后问还有多少逆序对,没时间写。。。
前提条件,对于一个个数位n的数组,正序对个数+逆序对个数 = 总对数= n*(n-1)
大概可能的思路是,归并排序的同时计算逆序对个数,计算到正好是我们需要翻转的那一层,记下一个个数k。
最后算出总的逆序对个数ans之后,之前算的那部分逆序对正好是完全算错的, ans - 2^(m-n)*(2^n*(2^n-1)) + 2*k,中间部分为所有的对数,
看得到多少楼
预处理左边能看到的楼。右边能看到的楼,总的看到的数量是左边可以看到的楼+右边可以看到的楼+1
预处理使用栈,如果发现现在需要入栈的楼比栈顶高了,就将它出栈。直到可以放进去位置,此时可以看到的楼的数量为栈的总大小
int n; int w[100005]; int l[100005],r[100005]; stack<int> stk; int main(){ cin>>n; for(int i=0;i<n;++i){ cin>>w[i]; } for(int i=0;i<n;++i){ if(stk.empty()){ stk.push(w[i]); } else{ while(!stk.empty() && stk.top()<=w[i]){ stk.pop(); } stk.push(w[i]); } l[i] = stk.size(); } while(!stk.empty()) stk.pop(); for(int i=n-1;i>=0;--i){ if(stk.empty()){ stk.push(w[i]); } else{ while(!stk.empty() && stk.top()<=w[i]){ stk.pop(); } stk.push(w[i]); } r[i] = stk.size(); } for(int i=0;i<n;++i){ int ans = 1; if(i>0){ ans+=l[i-1]; } if(i<n-1){ ans+=r[i+1]; } cout<<ans<<" "; }cout<<endl; }
最少可以休息几天
动态规划,分成三种情况,0上班,1运动,2休息,如果目前这个情况不合法,那么设置为-1
int dp[100005][3]; int seq[100005][2]; int n; // 0 work 1 sport 2 rest int main(){ cin>>n; for(int t = 0;t<2;++t) { for (int i = 0; i < n; ++i) { cin >> seq[i][t]; } } dp[0][0] = (seq[0][0] == 1) ? 0:-1; dp[0][1] = (seq[0][1] == 1) ? 0:-1; dp[0][2] = 1; for(int i=1;i<n;++i){ if(seq[i][0]) {// want work dp[i][0] = min(dp[i-1][1], dp[i-1][2]); if(dp[i][0] == -1){ dp[i][0] = dp[i-1][2]; } } else{ dp[i][0] = -1; } if(seq[i][1]) {// want work dp[i][1] = min(dp[i-1][0], dp[i-1][2]); if(dp[i][1] == -1){ dp[i][1] = dp[i-1][2]; } } else{ dp[i][1] = -1; } int m = 99999999; if(seq[i-1][0]){ m = min(m,dp[i-1][0]); } if(seq[i-1][1]){ m = min(m,dp[i-1][1]); } m = min(dp[i-1][2]+1, m+1); dp[i][2] = m; } // 最后在dp[n-1][0],dp[n-1][1],dp[n-1][2]之中选出最小的不为-1【合法】的结果 }