目录
1.剑指Offer
面试题59:滑动窗口最大值(牛客网无)
题目描述:
思路:
和最大子序和思想基本是一样的
用一个队列存放数组下标,设两个指针l
和r
,其中l
指向当前队列中数最大的数组下标,r
指向最后一个进队列的元素,如果新进元素比队尾大,那么就弹出队尾元素,因为队尾元素的生存能力已经不如新进的元素强,没有存在意义
代码:
剑指offer解法,超出时间限制不能通过leetcode
class Solution {
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
vector<int> maxSlidingWindow;
while(nums.size()>=k&&k>=1){
deque<int> q;
for(int i=0;i<nums.size();i++){
while(!q.empty()&&nums[i]>=nums[q.back()]){
q.pop_back();
}
q.push_back(i);
}
for(int i=k;i<nums.size();i++){
maxSlidingWindow.push_back(nums[q.front()]);
while(!q.empty()&&nums[i]>=nums[q.back()]){
q.pop_back();
}
if(!q.empty()&&q.front()<=int(i-k)){
q.pop_front();
}
q.push_back(i);
}
maxSlidingWindow.push_back(nums[q.front()]);
}
return maxSlidingWindow;
}
};
leetcode通过解法
class Solution
{
public:
vector<int> maxSlidingWindow(vector<int> &nums, int k)
{
vector<int> ans;
if (nums.empty())
return ans;
int q[nums.size() + 5];
memset(q, 0, sizeof(q));
int l = 0, r = 0;
for (int i = 0; i < nums.size(); ++i)
{
while (l <= r && q[l] <= i - k)//超出窗口,弹出元素
++l;
while (l <= r && nums[q[r]] < nums[i])//队尾元素生存能力差,弹出
--r;
q[++r] = i;//进队
if (i + 1 >= k)//窗口达到k,放入答案中
ans.push_back(nums[q[l]]);
}
return ans;
}
};
面试题30:包含min函数的栈
题目描述:定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数(时间复杂度应为O(1))。
思路:使用辅助栈
代码:
class Solution {
public:
stack<int> stack1,stack2;
void push(int value) {
stack1.push(value);
if(stack2.empty()||value<stack2.top()){
stack2.push(value);
}
}
void pop() {
if(stack1.top()==stack2.top()){
stack2.pop();
}
stack1.pop();
}
int top() {
return stack1.top();
}
int min() {
return stack2.top();
}
};
2.华为机试题
例1:汽水瓶
题目描述:
有这样一道智力题:“某商店规定:三个空汽水瓶可以换一瓶汽水。小张手上有十个空汽水瓶,她最多可以换多少瓶汽水喝?”答案是5瓶,方法如下:先用9个空瓶子换3瓶汽水,喝掉3瓶满的,喝完以后4个空瓶子,用3个再换一瓶,喝掉这瓶满的,这时候剩2个空瓶子。然后你让老板先借给你一瓶汽水,喝掉这瓶满的,喝完以后用3个空瓶子换一瓶满的还给老板。如果小张手上有n个空汽水瓶,最多可以换多少瓶汽水喝?
输入描述:
输入文件最多包含10组测试数据,每个数据占一行,仅包含一个正整数n(1<=n<=100),表示小张手上的空汽水瓶数。n=0表示输入结束,你的程序不应当处理这一行。
输出描述:
对于每组测试数据,输出一行,表示最多可以喝的汽水瓶数。如果一瓶也喝不到,输出0。
示例1
输入
3 10 81 0
输出
1 5 40
代码:
方法1:通过数学分析,最后获得的饮料数是总空瓶数整除2 。
#include <iostream>
using namespace std;
int main(){
int n;
while(cin>>n){
cout << n/2 << endl;
}
return 0;
}
方法2:递归问题
3个瓶子换1瓶水+1个空瓶子,两个瓶子换1瓶水+0个空瓶子,1个瓶子换0瓶水。
f(1) = 0
f(2) = 1
f(3) = 1
f(4) = f(2)+1 //4个瓶子,其中3个可以换1瓶水+1个空瓶,所以是f(2)+1
f(5) = f(3)+1 //3个瓶子换1瓶水+1个空瓶,所以是f(3)+1
...
f(n) = f(n-2)+1
#include <iostream>
using namespace std;
int f(int n){
if(n<=1) return 0;
if(n==2) return 1;
return f(n-2)+1;
}
int main(){
int n;
while(cin>>n){
cout << f(n) << endl;
}
return 0;
}
例2:删除字符串中出现次数最少的字符
题目描述:
实现删除字符串中出现次数最少的字符,若多个字符出现次数一样,则都删除。输出删除这些单词后的字符串,字符串中其它字符保持原来的顺序。
输入描述:
字符串只包含小写英文字母, 不考虑非法输入,输入的字符串长度小于等于20个字节。
输出描述:
删除字符串中出现次数最少的字符后的字符串。
示例1
输入
abcdd
输出
dd
代码:
#include <iostream>
using namespace std;
int main(){
string str;
while(cin>>str){
int a[26]={0};
int len=str.length();
for(int i=0;i<len;i++){ //统计字符个数
a[str[i]-'a']++;
}
int min=a[str[0]-'a']; //找到最小个数
for(int i=0;i<len;i++){
if(a[str[i]-'a']<min){
min=a[str[i]-'a'];
}
}
for(int i=0;i<len;i++){ //删除最小字符
if(a[str[i]-'a']>min){
cout<<str[i];
}
}
cout<<endl;
}
return 0;
}
#include <iostream>
#include <map>
using namespace std;
int main(){
string str;
while(cin>>str){
map<char,int> m;
for(char i='a';i<='z';i++){ //map置空
m[i]=0;
}
int min=999;
for(int i=0;i<str.length();i++){ //统计个数并找到最小的个数
m[str[i]]++;
if(m[str[i]]<min){
min=m[str[i]];
}
}
for(int i=0;i<str.length();i++){
if(m[str[i]]>min){
cout<<str[i];
}
}
cout<<endl;
}
return 0;
}
例3.合唱队
例1:首先计算每个数在最大递增子串中的位置
186 186 150 200 160 130 197 200 quene
1 1 1 2 2 1 3 4 递增计数
然后计算每个数在反向最大递减子串中的位置--->计算反向后每个数在最大递增子串中的位置
200 197 130 160 200 150 186 186 反向quene
1 1 1 2 3 2 3 3 递减计数
然后将每个数的递增计数和递减计数相加
186 186 150 200 160 130 197 200 quene
1 1 1 2 2 1 3 4 递增计数
3 3 2 3 2 1 1 1 递减计数
4 4 3 5 4 2 4 5 每个数在所在队列的人数+1(自己在递增和递减中被重复计算)
如160这个数
在递增队列中有2个人数
150 160
在递减队列中有2个人数
160 130
那么160所在队列中就有3个人
150 160 130
每个数的所在队列人数表达就是这个意思
总人数 - 该数所在队列人数 = 需要出队的人数
解析:动态规划,最大递增子序列
代码:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
void callIncSub(vector<int> queue,vector<int> &incNum){
for(int i=1;i<queue.size();i++){
for(int j=i-1;j>=0;j--){
if(queue[i]>queue[j]&&incNum[i]<incNum[j]+1){
incNum[i]=incNum[j]+1;
}
}
}
}
int main(){
int n;
int h;
while(cin>>n){
vector<int> queue;
vector<int> incNum(n,1);
vector<int> decNum(n,1);
vector<int> totalNum;
for(int i=0;i<n;i++){
cin>>h;
queue.push_back(h);
}
callIncSub(queue,incNum);
reverse(queue.begin(),queue.end());
callIncSub(queue,decNum);
reverse(decNum.begin(),decNum.end());
int max=0;
for(int i=0;i<n;i++){
totalNum.push_back(incNum[i]+decNum[i]);
if(totalNum[i]>max){
max=totalNum[i];
}
}
cout<<n-max+1<<endl;
}
return 0;
}