牛牛的字符反转
题意:给出一个数字n和k,我们可以进行的操作是将1-n的排列进行选择区间进行反转,问得到将1-n序列向右循环移动k个位置的序列所需要操作的最少的次数为多少。
思路:我们反过来思考,我们先将1-n向右进行循环位移k个单位,然后选择合适的区间进行反转,问回到1-n的排列所需要的操作次数为多少?我们先讨论特殊的,如果k为n的倍数的话,那显然不要进行操作即可。如果n=2的时候,最多也只需要操作1次,当n>2时,我们发现,如果k%n<=2的时候,我们只要进行最少2次操作即可,如:n=6,k=2,就是561234,先将下标区间为[2-n]进行反转得543216,然后将下标区间为[1-n-1]进行反转即可得到1-n,同理n=6,k=4也是如此,其余的就是先将两边进行反转得到局部右序,然后进行一次整体反转得到全部有序。
代码:
class Solution {
public:
/**
*
* @param n int整型 字符串长度n
* @param k int整型 循环右移次数k
* @return int整型
*/
int solve(int n, int k) {
// write code here
int tmp=k%n;
if(tmp==0) return 0;
else if(n==2) return 1;
else if(tmp==1||n-tmp==1) return 2;
else if(tmp==2||n-tmp==2) return 2;
return 3;
}
};牛牛的木板
题意:给你一个01序列,然后可以有k次机会将其中的0变为1,问最后最长的连续1长度为多少?
思路:一个双指针进行处理,区间修改也类似于用单调队列进行维护,我们维护一个区间,区间里面的0个个数最多就k个即可。
代码:
class Solution {
public:
/**
*
* @param n int整型
* @param m int整型
* @param a int整型vector
* @return int整型
*/
int solve(int n, int m, vector<int>& a) {
// write code here
int dp[2],maxNum=0,res=0;
dp[1]=dp[0]=0;
for(int i=0,j=0;j<n;j++){
dp[a[j]]++;
maxNum=max(maxNum,dp[1]);
while(j-i+1-maxNum>m){
dp[a[i]]--;
i++;
}
res=max(res,j-i+1);
}
return res;
}
};中序序列
题意:给出一颗二叉树的后序遍历和前序遍历,求最后的中序遍历的序列。
思路:一个很裸的题目,和我们已知前序和中序遍历,求后续遍历的思路一样,我们利用递归不断构建二叉树的左右子树既可以了。只是这里要注意的是我们如何确定二叉树的左右子树的范围。
代码:
class Solution {
public:
/**
* 返回所求中序序列
* @param n int整型 二叉树节点数量
* @param pre int整型vector 前序序列
* @param suf int整型vector 后序序列
* @return int整型vector
*/
vector<int> ans;
void build(int ll,int lr,vector<int> &pre,int rl,int rr,vector<int>& suf){
//这里的ll,lr表示的是先序遍历的序列范围,rl,rr表示的是后序遍历的序列范围
if(ll>lr) return;
if(ll==lr){
ans.push_back(pre[ll]);
return;
}
int pos;
for(int i=rl;i<=rr;i++){
if(suf[i]==pre[ll+1]){
pos=i; //找到当前父结点下的左子树的根节点
break;
}
}
int len=pos-rl;
build(ll+1,ll+1+len,pre,rl,pos,suf); //构建左子树
ans.push_back(pre[ll]);
build(len+ll+2,lr,pre,pos+1,rr-1,suf); //构建右子树
}
vector<int> solve(int n, vector<int>& pre, vector<int>& suf) {
// write code here
build(0,n-1,pre,0,n-1,suf);
return ans;
}
};
京公网安备 11010502036488号