程序员面试求职100题(1-10)

本帖题目均选自 何海涛剑指offer一书,欢迎大家与我一起做、讨论这些题目,共同享受编程和思考的乐趣,何乐而不为呢? 

1、在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。

答案 
杨氏矩阵的查找,可以分治,但一个比较好的解法是从第一行最后一列开始查找,决定往左还是往下移动。

#include <iostream>

using namespace std;
#define N 1024
int a[N][N]={{1,2,8,9},{2,4,9,12},{4,7,10,13},{6,8,11,15}};
int main(int argc,char *argv[])
{
	int m = 4,n = 4,t = 6,r,c;	
	r = 0;
	c = n - 1;
	bool find = false;
	while((r < m) && (c >= 0))
	{
		if(t == a[r][c])
		{
			find = true;
			break;
		}
		else
			if(t < a[r][c])
				c--;
			else
				r++;
	}
	printf("%d:",a[r][c]);
	puts(find?"存在":"不存在");
	return 0;
}

2输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并输出它的后序遍历序列。 (本题可以直接输出来,不用先还原出二叉树) 


答案: 递归的简单应用,前序遍历的根在最前面,在中序遍历里找到那个数,然后前序序列和中序序列的分解成为两部分,对这两部分在递归即可。可以直接生成后续遍历的序列,而不用重构出这棵树。

#include <iostream>
 
using namespace std;
 
int pre[1024],post[1024],in[1024];
 
bool can(int *pre,int *in,int *post,int fpre,int fin,int fpost,int len) {
int i;
        if (len <= 0) {
                return true;
        }
        for (i = 0; i < len; ++i) {
                if (pre[fpre] == in[fin + i]) {
                        break;
                }
        }
        if (i >= len) {
                return false;
        }
        if (!can(pre,in,post,fpre + 1,fin,fpost,i)) {
                return false;
        }
        if (!can(pre,in,post,fpre + i + 1,fin + i + 1, fpost + i,len - i - 1)) {
                return false;
        }
        post[fpost + len - 1] = pre[fpre];
        return true;
}
 
 
int main() {
int i,n;
        while (scanf("%d",&n) != EOF) {
                for (i = 0; i < n; ++i) {
                        scanf("%d",pre + i);
                }
                for (i = 0; i < n; ++i) {
                        scanf("%d", in + i);
                }
                if (can(pre,in,post,0,0,0,n)) {
                        for (i = 0; i < n; ++i) {
                                printf("%d ",post[i]);
                        }
                        puts("");
                }
                else {
                        puts("No");
                }
        }
        return 0;
}

3、把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。 (如果数组里有重复元素,怎么办?)

答案:  2分查找的扩充,考虑 [from,to]这段区间,mid = (from + to) / 2,如果a[mid] < a[to]  则最小值在前半段里,如果a[mid] > a[to], 这段区间发生了跳变,所以最小值在后半段区间里。相等时,当然我们可以比较a[mid]和a[from],但再相等就没办法了。偷懒的做法是直接从前后半段分别找,然后返回最小的,因此最差时间复杂度是O(n)。当存在相等的数时,可能达到最差时间复杂度。

#include<iostream>

using namespace std;
 
int a[1000005];
 
int find(int *a,int from,int to) {
        if (from == to - 1) {
                return (a[from] < a[to])?a[from]:a[to];
        }
        if (from == to) {
                return a[to];
        }
        int mid = (from + to) >> 1,x;
        if (a[mid] < a[to]) {
                x = find(a, from, mid - 1);
                if (x > a[mid]) {
                        x = a[mid];
                }
        }
        else if (a[mid] > a[to]) {
                x = find(a,mid + 1, to);
        }
        else {
                int  x1 = find(a, from, mid - 1);
                int  x2 = find(a, mid + 1, to );
                x = (x1 < x2)?x1:x2;
                if (x > a[mid]) {
                        x = a[mid];
                }
        }
        return x;
}
 
 
int main() {
int i,n;
        while (scanf("%d",&n) != EOF) {
                for (i = 0; i < n; ++i) {
                        scanf("%d", a + i);
                }
                printf("%d\n",find(a,0,n -1));
        }
        return 0;
}

4、大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项。斐波那契数列的定义如下:
     f(n) = 0   n = 0;
     f(n) = 1   n = 1
     f(n) = f(n - 1) + f(n - 2)


答案: 直接用定义递推求就可以。当然可以用O(n)空间来求保存出每一项,实际上保存最后两项即可。所以可以做到O(1)空间,O(n)时间。另外,斐波那契数列增长速度非常快,所以要用到long long。

#include<iostream>

using namespace std;

typedef long long ll;

int main(int argc,char *argv[])
{
	ll a,b;
	int i,n;
	while(scanf("%d",&n) != EOF)
	{
		if(n < 2)	
			printf("%d\n",n);
		else
		{
			a = 0;
			b = 1;
			printf("%4lld%4lld",a,b);
			for(i = 1;;)
			{
				a += b;
				printf("%4lld",a);
				if(++i == n)
				{
					printf("\n");
					break;
				}
				b += a;
				printf("%4lld",b);
				if(++i == n)
				{
					printf("\n");
					break;
				}
			}
		}
	}
	return 0;
}


5、 一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法。


答案: 简单递推,最后一次上一级或者两级,所以f(n) = f(n - 1) + f(n - 2)  所以结果也是斐波那契数列,除初始条件外,和第4题一样。 

#include<iostream>

using namespace std;
 
 
typedef long long ll;
int main()
{
	ll a,b;
	int i,n;
        while (scanf("%d",&n) != EOF)
		{
                if (n < 2) {
                        printf("%d\n",n);
                }
                else {
                        a = 1;
                        b = 1;
                        for (i = 1;;)
						{
                                a += b;
                                if (++i == n) 
								{
                                        printf("%lld\n",a);
                                        break;
                                }
                                b += a;
                                if (++i == n) 
								{
                                        printf("%lld\n",b);
                                        break;
                                }
 
                        }
                }
        }
        return 0;
}

6  一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。

 f(n) = f(n - 1) + f(n - 2) + f(n - 3) +...+f(0)  算出f(n) = 2^n

#include <iostream>

using namespace std;
 
 
typedef long long ll;
int main() {
int n;
    while (scanf("%d",&n) != EOF) {
        printf("%lld\n",((ll) 1) << (n - 1));
    }
    return 0;
}

7  我们可以用2*1的小矩形横着或者竖着去覆盖更大的矩形。请问用n个2*1的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法?

考虑  如果第一块横放还是竖着放,因为大矩形是2 * n的 所以 f(n) = f(n - 1) + f(n - 2)因此 还是斐波那契数。

#include <iostream>

using namespace std;
 
 
typedef long long ll;
int main() {
ll a,b;
int i,n;
    while (scanf("%d",&n) != EOF) {
        if (n < 2) {
            printf("%d\n",n);
        }
        else {
            a = 1;
            b = 1;
            for (i = 1;;) {
                a += b;
                if (++i == n) {
                    printf("%lld\n",a);
                    break;
                }
                b += a;
                if (++i == n) {
                    printf("%lld\n",b);
                    break;
                }
 
            }
        }
    }
    return 0;
}

8  输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下矩阵:

1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
则依次打印出数字1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10.
保存上下左右边界U D L R 每次打印最外一层,注意只有一行或者一列的情况。 边界值要控制好。

#include <iostream>
 
using namespace std;
 
int a[1024][1024];
 
int main() {
int i,j,m,n;
    while (scanf("%d%d",&m,&n) != EOF) {
        for (i = 0; i < m; ++i) {
            for (j = 0; j < n; ++j) {
                scanf("%d",&a[i][j]);
            }
        }
        int U = 0;
        int D = m - 1;
        int L = 0;
        int R = n - 1;
        for (;(U <= D) && (L <= R);++U,--D,++L,--R) {
            for (i = L; i <= R; ++i) {
                printf("%d ",a[U][i]);
            }
            for (i = U + 1; i <= D; ++i) {
                printf("%d ",a[i][R]);
            }
            if (U != D) {
                for (i = R - 1; i >= L; --i) {
                    printf("%d ",a[D][i]);
                }
            }
            if (L != R) {
                for (i = D - 1; i > U; --i) {
                    printf("%d ",a[i][L]);
                }
            }
        }
        puts("");
    }
 
    return 0;
}

9  输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列

其实就是弄个栈模拟,当前没处理的数,如果不等于栈顶元素就是压入栈,否则弹出栈。

10 输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。

后序遍历的话根在最后,从跟分开。找到左子树右子树两段,这两段分别是比根小的和比根大的(一定是连续的),然后分别递归判断。

#include <iostream>

using namespace std;
 
int a[10005];
 
bool help(int *a,int from,int to) {
int i,j;
    if (from >= to) {
        return true;
    }
    for (i = from; a[i] < a[to];++i)
    ;
    j = i - 1;
    for (;a[i] > a[to];++i)
    ;
    return (i == to) && help(a, from, j) && help(a, j, to - 1);
     
 
}
 
int main() {
int n,i;
    while (scanf("%d",&n) != EOF) {
        for (i = 0; i < n; ++i) {
            scanf("%d",a + i);
        }
        puts(help(a,0,n - 1)?"Yes":"No");
    }
    return 0;
}


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值