牛牛的字符反转
题意:给出一个数字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; } };