题目链接:面试常考算法题(一)
题目1:请把一张窄纸条竖着放在桌上,然后从纸条的下边向上对折,压出折痕后再展开。此时有1条折痕,突起的一面向指向纸条的背面,这条折痕叫做“下”折痕;突起的向指向纸条正面的折痕叫做“上”折痕。如果每次都从下边向上进行对折,对折N次。请从上到下计算出所有折痕的朝向。给定折的次数n,请返回从上到下的折痕的数组,若为下折痕则对应元素为”down”,若为上折痕则为”up”。
测试样例:
1
返回:["down"]
分析:这题首先容易想到的是找规律,首先我们先对前几项结果进行观察:
n = 1, size = 1:
"down"
,
n = 2, size = 3:
"down"
,
"down"
,
"up"
n = 3, size = 7:
"down"
,
"down"
,
"up"
,
"down"
,
"down"
,
"up"
,
"up"
可以观察到每次迭代的时候,数组的新size是前面size的2倍加上1,即size = 2*size+1,
前面的部分和上一组完全
相同,最中间的值恒为
"down"
,后半部分字节将前面的值翻转
并取反即可得到。talk is cheap,show me the
code:
class FoldPaper {
public:
vector<string> foldPaper(int n) {
vector<string> res;
if(n==1)
res.push_back("down");
else{
vector<string> v = foldPaper(n-1);
for(int i = 0;i<v.size();++i){
res.push_back(v[i]);
}
res.push_back("down");
reverse(v.begin(),v.end());
for(int i = 0;i<v.size();++i){
if(v[i]=="down")
res.push_back("up");
else
res.push_back("down");
}
}
return res;
}
};
另一条思路是转化为二叉树的中序遍历,构建一颗二叉树,根节点是down,左子树的根是down,右子树的根节点是up。可以构造一个满二叉树,talk is cheap,show me the code:
class FoldPaper {
public:
vector<string> foldPaper(int n) {
// write code here
vector<string> vec;
pushs(vec,n,"down");
return vec;
}
//中序遍历程序
void pushs(vector<string> &vec,int n,string str)
{
if(n>0)
{
pushs(vec,n-1,"down");
vec.push_back(str);
pushs(vec,n-1,"up");
}
}
};
更多讨论见折纸问题。
题目2:
对于一个矩阵,请设计一个算法从左上角(mat[0][0])开始,顺时针打印矩阵元素。
给定int矩阵
mat
,以及它的维数
n
x
m
,请返回一个数组,数组中的元素为矩阵元素的顺时针输出。
测试样例:
[[1,2],[3,4]],2,2
返回:[1,2,4,3]
分析:基本思路是不管简化矩阵,先顺时针打印矩阵外围的一圈,然后不断缩小矩阵即可,最后讨论一下只有一行或者一列的情形,talk is cheap,show me the code:
class Printer {
public:
void clockwisePrint(const vector<vector<int>> &mat,vector<int> &res,int row1,int col1,int row2,int col2){
//左上角(row1,col1)右下角(row2,col2)
int i = row1,j=col1;
while(j<=col2) //上一行向右
res.push_back(mat[i][j++]);
--j,++i;
while(i<=row2) //右一行向下
res.push_back(mat[i++][j]);
--i,--j;
if(row1 == row2 || col1 == col2) //只又一列或一行时,不向左,也不向上
return;
while(j>=col1) //下一行向左
res.push_back(mat[i][j--]);
++j,--i;
while(i>row1) //左一行向上,不打印左上角
res.push_back(mat[i--][j]);
}
vector<int> clockwisePrint(vector<vector<int> > mat, int n, int m) {
int row1,row2,col1,col2;
std::vector<int> res;
for(row1 = 0,col1=0,row2=n-1,col2=m-1;row1<=row2 && col1<=col2;row1++,col1++,row2--,col2--)
clockwisePrint(mat,res,row1,col1,row2,col2);
return res;
}
};
题目3:
有一个NxN整数矩阵,请编写一个算法,将矩阵顺时针旋转90度。
给定一个NxN的矩阵,和矩阵的阶数N,请返回旋转后的NxN矩阵,保证N小于等于300。
测试样例:
[[1,2,3],[4,5,6],[7,8,9]],3
返回:[[7,4,1],[8,5,2],[9,6,3]]
分析:找出旋转后的矩阵每个元素的位置在原来矩阵中对应位置之间的关系即可,talk is cheap,show me the code:
class Rotate {
public:
vector<vector<int> > rotateMatrix(vector<vector<int> > mat, int n) {
vector<vector<int> > vmat(n,vector<int>(n,0));
for(int i = 0;i<n;++i){
for(int j = 0;j<n;++j)
vmat[i][j] = mat[n-1-j][i];
}
return vmat;
}
};
题目4:
对于一个矩阵,请设计一个算法,将元素按“之”字形打印。具体见样例。
给定一个整数矩阵
mat
,以及他的
维数nxm,请返回一个数组,其中元素依次为打印的数字。
测试样例:
[[1,2,3],[4,5,6],[7,8,9],[10,11,12]],4,3
返回:[1,2,3,6,5,4,7,8,9,12,11,10]
分析:行是奇数从左到右打印,行是偶数从右到左打印,talk is cheap,show me the code:
class Printer {
public:
vector<int> printMatrix(vector<vector<int> > mat, int n, int m) {
vector<int> res;
int i = 0;
while(i<n){
if(i%2==0){
for(int j = 0;j<m;++j)
res.push_back(mat[i][j]);
}
else{
for(int j = m-1;j>=0;--j)
res.push_back(mat[i][j]);
}
++i;
}
return res;
}
};
题目5:
对于一个字符串,和字符串中的某一位置,请设计一个算法,将包括i位置在内的左侧部分移动到右边,将右侧部分移动到左边。
给定字符串
A
和它的长度
n
以及特定位置
p
,请返回旋转后的结果。
测试样例:
"ABCDEFGH",8,4
返回:"FGHABCDE"
分析:参考博客字符串移位的解题技巧。talk is cheap,show me the code:
class StringRotation {
public:
string rotateString(string A, int n, int p) {
return A.substr(p+1)+A.substr(0,p+1);
}
};