程序员面试题精选100题:41-50解题报告

程序员面试题精选100题(41)-把数组排成最小的数[算法]  

题目:输入一个正整数数组,将它们连接起来排成一个数,输出能排出的所有数字中最小的一个。例如输入数组{32,  321},则输出这两个能排成的最小数字32132。请给出解决问题的算法,并证明该算法。

根据题目的要求,两个数字m和n排成的数字mn和nm,如果mn<nm,那么我们应该输出mn,也就是m应该排在n的前面,也就是m小于n;反之,如果nm<mn,n小于m。如果mn==mn,m等于n。

接下来我们考虑怎么去拼接数字,即给出数字m和n,怎么得到数字mn和nm并比较它们的大小。直接用数值去计算不难办到,但需要考虑到的一个潜在问题是m和n都在int能表达的范围内,但把它们拼起来的数字mn和nm就不一定能用int表示了。所以我们需要解决大数问题。一个非常直观的方法就是把数字转换成字符串。

 

===========================================================================

程序员面试题精选100题(42)-旋转数组的最小元素[算法]  

题目:把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个排好序的数组的一个旋转,输出旋转数组的最小元素。例如数组{3, 4, 5, 1, 2}为{1, 2, 3, 4, 5}的一个旋转,该数组的最小值为1。

分析:遍历可以获得最小元素,所以考察的复杂度肯定小于O(n),那基本只有O(logn)了,那就是折半查找了。怎么利用折半呢?

判断l-mid是否递增(a[l]<=a[mid]),如果是那么结果在右边,l=mid+1;否则还在左边,迭代或者递归。

终止条件是l=r.

特殊情况a[l]<=a[r],直接返回a[l]。。。

 

扩展:

===========================================================================

程序员面试题精选100题(43)-n个骰子的点数[算法]  

题目:把n个骰子扔在地上,所有骰子朝上一面的点数之和为S。输入n,打印出S的所有可能的值出现的概率。

分析:递推关系:f(n,s)=sum(f(n-1,s-k))*1/6,1<=k<=6

初始f(0,0)=1,f(0,1….6n)=0;0<=s<=6n

结果:f(n,n….6n)

我不知道这个叫不叫动态规划哦,不过和动态规划是一个路子。

空间优化:可以使用滚动数组优化为只用一个数组存储,没必要使用n维存储,s从右向左。

 

直接递归会重复计算,也可以使用记忆递归避免重复。

===========================================================================

程序员面试题精选100题(44)-数值的整数次方[算法]  

题目:实现函数double Power(double base, int exponent),求base的exponent次方。不需要考虑溢出。

坑不少呐,负数,除零,,,,而且还可以分治二分优化。。。。。

===========================================================================

程序员面试题精选100题(45)-Singleton(C/C++/C#)  

题目:设计一个类,我们只能生成该类的一个实例。

分析:只能生成一个实例的类是实现了Singleton模式的类型。

我们只需要在最开始调用Singleton4_getInstance(可能来自一个线程,也可能来自多个线程)的时候需要加锁。当实例已经创建之后,我们就不再需要作加锁操作,从而在后续调用Singleton4_getInstance时性能得到提升。

 

http://blog.csdn.net/nanjunxiao/article/details/8974639

===========================================================================

程序员面试题精选100题(46)-对称子字符串的最大长度[算法]  

题目:输入一个字符串,输出该字符串中对称的子字符串的最大长度。比如输入字符串“google”,由于该字符串里最长的对称子字符串是“goog”,因此输出4。

分析:O(n^3)的能想到,O(n^2)的O(n)的没想到。。。智商拙计

O(n^2)以每个字符为中心,向两边扩展,判断是否为回文,O(n),n个中心所以复杂度为O(n^2)。

相对于暴力O(n^3),减少了两端中间是否回文的判断,肯定是回文的。

O(n)的后缀树,不会,找个时间看看。。。

===========================================================================

程序员面试题精选100题(47)-数组中出现次数超过一半的数字[算法]  

题目:数组中有一个数字出现的次数超过了数组长度的一半,找出这个数字。

分析:1.hash

2.血拼。。。最后剩下的就是。

===========================================================================

程序员面试题精选100题(48)-二叉树两结点的最低共同父结点[数据结构]  

输入二叉树中的两个结点,输出这两个结点在数中最低的共同父结点。

第一变种是二叉树是一种特殊的二叉树:查找二叉树。也就是树是排序过的,位于左子树上的结点都比父结点小,而位于右子树的结点都比父结点大。我们只需要从根结点开始和两个结点进行比较。如果当前结点的值比两个结点都大,则最低的共同父结点一定在当前结点的左子树中。如果当前结点的值比两个结点都小,则最低的共同父结点一定在当前结点的右子树中。

第二个变种是树不一定是二叉树,每个结点都有一个指针指向它的父结点。于是我们可以从任何一个结点出发,得到一个到达树根结点的单向链表。因此这个问题转换为两个单向链表的第一个公共结点。我们在本面试题系列的第35讨论了这个问题。

现在我们回到这个问题本身。所谓共同的父结点,就是两个结点都出现在这个结点的子树中。因此我们可以定义一函数,来判断一个结点的子树中是不是包含了另外一个结点。这不是件很难的事,我们可以用递归的方法来实现:

这种会重复计算。接着我们来分析一下这个方法的效率。函数HasNode的本质就是遍历一棵树,其时间复杂度是O(n)(n是树中结点的数目)。由于我们根结点开始,要对每个结点调用函数HasNode。因此总的时间复杂度是O(n2)。

我的想法是先序递归遍历,每个节点存储从根到该节点的路径,只需递归一次,最终找到两个节点,两个路径最后一个相等的即为结果。但明显空间使用较多。

答案给出了一种方法,但需要递归两遍来找到两个节点,同时得到路径。。。

===========================================================================

程序员面试题精选100题(49)-复杂链表的复制[算法]  

 下图是一个含有5个结点的该类型复杂链表。图中实线箭头表示m_pNext指针,虚线箭头表示m_pSibling指针。为简单起见,指向NULL的指针没有画出。

                  

                

请完成函数ComplexNode* Clone(ComplexNode* pHead),以复制一个复杂链表。

 

维护一个hash_map <N,N’>方便定位subing,O(n)复杂度

答案没看。。。。

===========================================================================

程序员面试题精选100题(50)-树的子结构[数据结构]  

输入两棵二叉树A和B,判断树B是不是A的子结构。

例如,下图中的两棵树A和B,由于A中有一部分子树的结构和B是一样的,因此B就是A的子结构。

                1                                                  8
              /   \                                               /   \
             8    7                                            9    2
            /   \
          9    2
               /  \
              4  7

 

递归:

Booldigui(Tree* A,Tree* B)

{

         If(NULL == B)

                   Return true;

         If(NULL == A)

                   Return false;

         If(A->data == B->data)

         {

                   Return digui(A->l,B->l)&& digui(A->r,B->r);

}

Else

{

         Return digui(A->l,B)|| digui(A->r,B);

}

}

没问题吧,不用答案的那种先递归找到相同根节点,在递归判断是否相同子树。。。。两个递归揉到一个递归里了。。。

你可能感兴趣的:(面试题,剑指offer100题)