40.百度研发笔试题
引用自:zp155334877
1)设计一个栈结构,满足一下条件:min,push,pop 操作的时间复杂度为O(1)。
ANSWER
Have done this.
2)一串首尾相连的珠子(m 个),有N 种颜色(N<=10),
设计一个算法,取出其中一段,要求包含所有N 中颜色,并使长度最短。
并分析时间复杂度与空间复杂度。
ANSWER
Use a sliding window and a counting array, plus a counter which monitors the num of zero slots in counting array. When there is still zero slot(s), advance the window head, until there is no zero slot. Then shrink the window until a slot comes zero. Then one candidate segment of (window_size + 1) is achieved. Repeat this. It is O(n) algorithm since each item is swallowed and left behind only once, and either operation is in constant time.
int shortestFullcolor(int a[], int n, int m) {
int c[m], ctr = m;
int h=0, t=0;
int min=n;
while (1) {
while (ctr > 0 && h<n) {
if (c[a[h]] == 0) ctr --;
c[a[h]] ++;
h++;
}
if (h>=n) return min;
while (1) {
c[a[t]] --;
if (c[a[t]] == 0) break;
t++;
}
if (min > h-t) min = h-t;
t++; ctr++;
}
}
3)设计一个系统处理词语搭配问题,比如说中国和人民可以搭配,
则中国人民人民中国都有效。要求:
系统每秒的查询数量可能上千次;
词语的数量级为10W;
*每个词至多可以与1W 个词搭配
当用户输入中国人民的时候,要求返回与这个搭配词组相关的信息。
ANSWER
This problem can be solved in three steps:
- identify the words
- recognize the phrase
- retrieve the information
Solution of 1: The most trivial way to efficiently identify the words is hash table or BST. A balanced BST with 100 words is about 17 levels high. Considering that 100k is not a big number, hashing is enough.
Solution of 2: Since the phrase in this problem consists of only 2 words, it is easy to split the words. There won’t be a lot of candidates. To find a legal combination, we need the “matching” information. So for each word, we need some data structure to tell whether a word can co-occur with it. 100k is a bad number -- cannot fit into a 16bit digit. However, 10k*100k is not too big, so we can simply use array of sorted array to do this. 1G integers, or 4G bytes is not a big number, We can also use something like VInt to save a lot of space. To find an index in a 10k sorted array, 14 comparisons are enough.
Above operation can be done in any reasonable work-station's memory very fast, which should be the result of execution of about a few thousands of simple statements.
Solution of 3: The information could be to big to fit in the memory. So a B-tree may be adopted to index the contents. Caching techniques is also helpful. Considering there are at most 10^9 entries, a 3 or 4 level of B-tree is okay, so it will be at most 5 disk access. However, there are thousands of requests and we can only do hundreds of disk seeking per second. It could be necessary to dispatch the information to several workstations.
41.求固晶机的晶元查找程序
晶元盘由数目不详的大小一样的晶元组成,晶元并不一定全布满晶元盘,
照相机每次这能匹配一个晶元,如匹配过,则拾取该晶元,
若匹配不过,照相机则按测好的晶元间距移到下一个位置。
求遍历晶元盘的算法求思路。
ANSWER
Dont understand.
42.请修改append 函数,利用这个函数实现:
两个非降序链表的并集,1->2->3 和2->3->5 并为1->2->3->5
另外只能输出结果,不能修改两个链表的数据。
ANSWER
I don’t quite understand what it means by “not modifying linked list’s data”. If some nodes will be given up, it is weird for this requirement.
Node head(Node h1, Node h2) {
if (h1==NULL) return h2;
if (h2==NULL) return h1;
Node head;
if (h1->data < h2->data) {
head =h1; h1=h1->next;
} else {
head = h2; h2=h2->next;
}
Node p = head;
while (h1!=NULL || h2!=NULL) {
Node candi;
if (h1!=NULL && h2 != NULL && h1->data < h2->data || h2==NULL) {
candi = h1; h1=h1->next;
} else {
candi = h2; h2=h2->next;
}
}
if (candi->data == p->data) delete(candi);
else {
p->next = candi; p=candi;
}
return head;
}
43.递归和非递归俩种方法实现二叉树的前序遍历。
ANSWER
void preorderRecursive(TreeNode * node) {
if (node == NULL) return;
visit(node);
preorderRecursive(node->left);
preorderRecursive(node->right);
}
For non-recursive traversals, a stack must be adopted to replace the implicit program stack in recursive programs.
void preorderNonrecursive(TreeNode node) {
stack<TreeNode > s;
s.push(node);
while (!s.empty()) {
TreeNode * n = s.pop();
visit(n);
if (n->right!=NULL) s.push(n->right);
if (n->left!=NULL) s.push(n->left);
}
}
void inorderNonrecursive(TreeNode node) {
stack<TreeNode > s;
TreeNode * current = node;
while (!s.empty() || current != NULL) {
if (current != NULL) {
s.push(current);
current = current->left;
} else {
current = s.pop();
visit(current);
current = current->right;
}
}
}
Postorder nonrecursive traversal is the hardest one. However, a simple observation helps that the node first traversed is the node last visited. This recalls the feature of stack. So we could use a stack to store all the nodes then pop them out altogether.
This is a very elegant solution, while takes O(n) space.
Other very smart methods also work, but this is the one I like the most.
void postorderNonrecursive(TreeNode node) {
// visiting occurs only when current has no right child or last visited is his right child
stack<TreeNode > sTraverse, sVisit;
sTraverse.push(node);
while (!sTraverse.empty()) {
TreeNode * p = sTraverse.pop();
sVisit.push(p);
if (p->left != NULL) sTraverse.push(p->left);
if (p->right != NULL) sTraverse.push(p->right);
}
while (!sVisit.empty()) {
visit(sVisit.pop);
}
}
44.腾讯面试题:
1.设计一个魔方(六面)的程序。
ANSWER
This is a problem to test OOP.
The object MagicCube must have following features
1) holds current status
2) easily doing transform
3) judge whether the final status is achieved
4) to test, it can be initialized
5) output current status
public class MagicCube {
// 6 faces, 9 chips each face
private byte chips[54];
static final int X = 0;
static final int Y = 1;
static final int Z = 1;
void transform(int direction, int level) {
switch direction: {
X : { transformX(level); break; }
Y : { transformY(level); break; }
Z : { transformZ(level); break; }
default: throw new RuntimeException(“what direction?”);
}
void transformX(int level) { … }
}
}
// really tired of making this...
}
2.有一千万条短信,有重复,以文本文件的形式保存,一行一条,有重复。
请用5 分钟时间,找出重复出现最多的前10 条。
ANSWER
10M msgs, each at most 140 chars, that’s 1.4G, which can fit to memory.
So use hash map to accumulate occurrence counts.
Then use a heap to pick maximum 10.
3.收藏了1 万条url,现在给你一条url,如何找出相似的url。(面试官不解释何为相似)
ANSWER
What a SB interviewer... The company name should be claimed and if I met such a interviewer, I will contest to HR. The purpose of interview is to see the ability of communication. This is kind of single side shutdown of information exchange.
My first answer will be doing edit distance to the url and every candidate. Then it depends on what interviewer will react. Other options includes: fingerprints, tries...
45.雅虎:
1.对于一个整数矩阵,存在一种运算,对矩阵中任意元素加一时,需要其相邻(上下左右)
某一个元素也加一,现给出一正数矩阵,判断其是否能够由一个全零矩阵经过上述运算得到。
ANSWER
A assignment problem. Two ways to solve. 1: duplicate each cell to as many as its value, do Hungarian algorithm. Denote the sum of the matrix as M, the edge number is 2M, so the complexity is 2MM; 2: standard maximum flow. If the size of matrix is NxN, then the algorithm using Ford Fulkerson algorithm is MNN.
too complex... I will do this when I have time...
2.一个整数数组,长度为n,将其分为m 份,使各份的和相等,求m 的最大值
比如{3,2,4,3,6} 可以分成{3,2,4,3,6} m=1;
{3,6}{2,4,3} m=2
{3,3}{2,4}{6} m=3 所以m 的最大值为3
ANSWER
Two restrictions on m, 1) 1 <= m <= n; 2) Sum(array) mod m = 0
NOTE: no hint that a[i]>0, so m could be larger than sum/max;
So firstly prepare the candidates, then do a brute force search on possible m’s.
In the search , a DP is available, since if f(array, m) = OR_i( f(array-subset(i), m) ), where Sum(subset(i)) = m.
int maxShares(int a[], int n) {
int sum = 0;
int i, m;
for (i=0; i<n; i++) sum += a[i];
for (m=n; m>=2; m--) {
if (sum mod m != 0) continue;
int aux[n]; for (i=0; i<n; i++) aux[i] = 0;
if (testShares(a, n, m, sum, sum/m, aux, sum/m, 1)) return m;
}
return 1;
}
int testShares(int a[], int n, int m, int sum, int groupsum, int[] aux, int goal, int groupId) {
if (goal == 0) {
groupId++;
if (groupId == m+1) return 1;
}
for (int i=0; i<n; i++) {
if (aux[i] != 0) continue;
aux[i] = groupId;
if (testShares(a, n, m, sum, groupsum, aux, goal-a[i], groupId)) {
return 1;
}
aux[i] = 0;
}
}
Please do edge cutting yourself, I’m quite enough of this...
46.搜狐:
四对括号可以有多少种匹配排列方式?比如两对括号可以有两种:()()和(())
ANSWER:
Suppose k parenthesis has f(k) permutations, k is large enough. Check the first parenthesis, if there are i parenthesis in it then, the number of permutations inside it and out of it are f(i) and f(k-i-1), respectively. That is
f(k) = Sumi=[0,k-1](f(i)*f(k-i-1));
which leads to the k’th Catalan number.
47.创新工场:
求一个数组的最长递减子序列比如{9,4,3,2,5,4,3,2}的最长递减子序列为{9,5,
4,3,2}
ANSWER:
Scan from left to right, maintain a decreasing sequence. For each number, binary search in the decreasing sequence to see whether it can be substituted.
int[] findDecreasing(int[] a) {
int[] ds = new int[a.length];
Arrays.fill(ds, 0);
int dsl = 0;
int lastdsl = 0;
for (int i=0; i<a.length; i++) {
// binary search in ds to find the first element ds[j] smaller than a[i]. set ds[j] = a[i], or append a[i] at the end of ds
int s=0, t=dsl-1;
while (s<=t) {
int m = s+(t-s)/2;
if (ds[m] < a[i]) {
t = m - 1;
} else {
s = m + 1;
}
}
// now s must be at the first ds[j]<a[i], or at the end of ds[]
ds[s] = a[i];
if (s > dsl) { dsl = s; lastdsl = i; }
}
// now trace back.
for (int i=lastdsl-1, j=dsl-1; i>=0 && j >= 0; i--) {
if (a[i] == ds[j]) { j --; }
else if (a[i] < ds[j]) { ds[j--] = a[i]; }
}
return Arrays.copyOfRange(ds, 0, dsl+1);
}
48.微软:
一个数组是由一个递减数列左移若干位形成的,比如{4,3,2,1,6,5}
是由{6,5,4,3,2,1}左移两位形成的,在这种数组中查找某一个数。
ANSWER:
The key is that, from the middle point of the array, half of the array is sorted, and the other half is a half-size shifted sorted array. So this can also be done recursively like a binary search.
int shiftedBinarySearch(int a[], int k) {
return helper(a, k, 0, n-1);
}
int helper(int a[], int k, int s, int t) {
if (s>t) return -1;
int m = s + (t-s)/2;
if (a[m] == k) return m;
else if (a[s] >= k && k > a[m]) return helper(a, k, s, m-1);
else return helper(a, k, m+1, e);
}
49.一道看上去很吓人的算法面试题:
如何对n 个数进行排序,要求时间复杂度O(n),空间复杂度O(1)
ANSWER:
So a comparison sort is not allowed. Counting sort’s space complexity is O(n).
More ideas must be exchanged to find more conditions, else this is a crap.
50.网易有道笔试:
1.求一个二叉树中任意两个节点间的最大距离,两个节点的距离的定义是这两个节点间边
的个数,
比如某个孩子节点和父节点间的距离是1,和相邻兄弟节点间的距离是2,优化时间空间复
杂度。
ANSWER:
Have done this before.
如果除去此节点和与其相关的边,有向图不再连通,描述算法。
ANSWER:
Have done this before.
51.和为n 连续正数序列。
题目:输入一个正数n,输出所有和为n 连续正数序列。
例如输入15,由于1+2+3+4+5=4+5+6=7+8=15,所以输出3 个连续序列1-5、4-6 和7-8。
分析:这是网易的一道面试题。
ANSWER:
It seems that this can be solved by factorization. However, factorization of large n is impractical!
Suppose n=i+(i+1)+...+(j-1)+j, then n = (i+j)(j-i+1)/2 = (jj - ii + i + j)/2
=> j^2 + j + (i-i^2-2n) = 0 => j=sqrt(i^2-i+1/4+2n) - 1/2
We know 1 <= i < j <= n/2 + 1
So for each i in [1, n/2], do this arithmetic to check if there is a integer answer.
int findConsecutiveSequence(int n) {
int count = 0;
for (int i=1; i<=n/2; i++) {
int sqroot = calcSqrt(4ii+8n-4i+1);
if (sqroot == -1) continue;
if ((sqroot & 1) == 1) {
System.out.println(i+”-” + ((sqroot-1)/2));
count ++;
}
}
return count;
}
Use binary search to calculate sqrt, or just use math functions.
52.二元树的深度。
题目:输入一棵二元树的根结点,求该树的深度。
从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为
树的深度。
例如:输入二元树:
10
/ \
6 14
/ / \
4 12 16
输出该树的深度3。
二元树的结点定义如下:
struct SBinaryTreeNode // a node of the binary tree
{
int m_nValue; // value of node
SBinaryTreeNode m_pLeft; // left child of node
SBinaryTreeNode m_pRight; // right child of node
};
分析:这道题本质上还是考查二元树的遍历。
ANSWER:
Have done this.
53.字符串的排列。
题目:输入一个字符串,打印出该字符串中字符的所有排列。
例如输入字符串abc,则输出由字符a、b、c 所能排列出来的所有字符串
abc、acb、bac、bca、cab 和cba。
分析:这是一道很好的考查对递归理解的编程题,
因此在过去一年中频繁出现在各大公司的面试、笔试题中。
ANSWER:
Full permutation generation. I will use another technique that swap two neighboring characters each time. It seems that all the characters are different. I need to think about how to do it when duplications is allowed. Maybe simple recursion is better for that.
void generatePermutation(char s[], int n) {
if (n>20) { error(“are you crazy?”); }
byte d[n];
int pos[n], dpos[n]; // pos[i], the position of i’th number, dpos[i] the number in s[i] is the dpos[i]’th smallest
qsort(s); // I cannot remember the form of qsort in C...
memset(d, -1, sizeof(byte)*n);
for (int i=0; i<n; i++) pos[i]=i, dpos[i]=i;
int r;
while (r = findFirstAvailable(s, d, pos, n)) {
if (r== -1) return;
swap(s, pos, dpos, d, r, r+d[r]);
for (int i=n-1; i>dpos[r]; i--)
d[i] = -d[i];
}
}
int findFirstAvailable(char s[], byte d[], int pos[], int n) {
for (int i=n-1; i>1; i--) {
if (s[pos[i]] > s[pos[i]+d[pos[i]]]) return pos[i];
}
return -1;
}
void swap(char s[], int pos[], int dpos[], byte d[], int r, int s) {
aswap(s, r, s);
aswap(d, r, s);
aswap(pos, dpos[r], dpos[s]);
aswap(dpos, r, s);
}
Maybe full of bugs. Please refer to algorithm manual for explansion.
Pros: Amotized O(1) time for each move. Only two characters change position for each move.
Cons: as you can see, very complicated. Extra space needed.
54.调整数组顺序使奇数位于偶数前面。
题目:输入一个整数数组,调整数组中数字的顺序,使得所有奇数位于数组的前半部分,
所有偶数位于数组的后半部分。要求时间复杂度为O(n)。
ANSWER:
This problem makes me recall the process of partition in quick sort.
void partition(int a[], int n) {
int i=j=0;
while (i < n && (a[i] & 1)==0) i++;
if (i==n) return;
swap(a, i++, j++);
while (i<n) {
if ((a[i] & 1) == 1) {
swap(a, i, j++);
}
i++;
}
}
- 题目:类CMyString 的声明如下:
class CMyString
{
public:
CMyString(char pData = NULL);
CMyString(const CMyString& str);
~CMyString(void);
CMyString& operator = (const CMyString& str);
private:
char m_pData;
};
请实现其赋值运算符的重载函数,要求异常安全,即当对一个对象进行赋值时发生异常,对
象的状态不能改变。
ANSWER
Pass...
56.最长公共字串。
题目:如果字符串一的所有字符按其在字符串中的顺序出现在另外一个字符串二中,
则字符串一称之为字符串二的子串。
注意,并不要求子串(字符串一)的字符必须连续出现在字符串二中。
请编写一个函数,输入两个字符串,求它们的最长公共子串,并打印出最长公共子串。
例如:输入两个字符串BDCABA 和ABCBDAB,字符串BCBA 和BDAB 都是是它们的最长公共子串,则输出它们的长度4,并打印任意一个子串。
分析:求最长公共子串(Longest Common Subsequence, LCS)是一道非常经典的动态规划
题,因此一些重视算法的公司像MicroStrategy 都把它当作面试题。
ANSWER:
Standard DP...
lcs(ap1, bp2) = max{ lcs(p1,p2)+1, lcs(p1, bp2), lcs(ap1, p2)}
int LCS(char p1, char p2) {
int l1= strlen(p1)+1, l2=strlen(p2)+1;
int a[l1l2];
for (int i=0; i<l1; i++) a[il2] = 0;
for (int i=0; i<l2; i++) a[i] = 0;
for (int i=1; i<l1; i++) {
for (int j=1; j<l2; j++) {
int max = MAX(a[(i-1)l2+l1], a[il2+l1-1]);
if (p1[i-1] == p2[j-1]) {
max = (max > 1 + a[(i-1)l2+j-1]) ? max : 1+a[(i-1)l2+j-1];
}
}
}
return a[l1*l2-1];
}
57.用俩个栈实现队列。
题目:某队列的声明如下:
template<typename T> class CQueue
{
public:
CQueue() {}
~CQueue() {}
void appendTail(const T& node); // append a element to tail
void deleteHead(); // remove a element from head
private:
Stack<T> m_stack1;
Stack<T> m_stack2;
};
分析:从上面的类的声明中,我们发现在队列中有两个栈。
因此这道题实质上是要求我们用两个栈来实现一个队列。
相信大家对栈和队列的基本性质都非常了解了:栈是一种后入先出的数据容器,
因此对队列进行的插入和删除操作都是在栈顶上进行;队列是一种先入先出的数据容器,
我们总是把新元素插入到队列的尾部,而从队列的头部删除元素。
ANSWER
Traditional problem in CLRS.
void appendTail(const T& node) {
m_stack1.push(node);
}
T getHead() {
if (!m_stack2.isEmpty()) {
return m_stack2.pop();
}
if (m_stack1.isEmpty()) error(“delete from empty queue”);
while (!m_stack1.isEmpty()) {
m_stack2.push(m_stack1.pop());
}
return m_stack2.pop();
}
58.从尾到头输出链表。
题目:输入一个链表的头结点,从尾到头反过来输出每个结点的值。链表结点定义如下:
struct ListNode
{
int m_nKey;
ListNode* m_pNext;
};
分析:这是一道很有意思的面试题。
该题以及它的变体经常出现在各大公司的面试、笔试题中。
ANSWER
Have answered this...
59.不能被继承的类。
题目:用C++设计一个不能被继承的类。
分析:这是Adobe 公司2007 年校园招聘的最新笔试题。
这道题除了考察应聘者的C++基本功底外,还能考察反应能力,是一道很好的题目。
ANSWER:
I don’t know c++.
Maybe it can be done by implement an empty private default constructor.
60.在O(1)时间内删除链表结点。
题目:给定链表的头指针和一个结点指针,在O(1)时间删除该结点。链表结点的定义如下:
struct ListNode
{
int m_nKey;
ListNode m_pNext;
};
函数的声明如下:
void DeleteNode(ListNode pListHead, ListNode* pToBeDeleted);
分析:这是一道广为流传的Google 面试题,能有效考察我们的编程基本功,还能考察我们
的反应速度,
更重要的是,还能考察我们对时间复杂度的理解。
ANSWER:
Copy the data from tobedeleted’s next to tobedeleted. then delete tobedeleted. The special case is tobedelete is the tail, then we must iterate to find its predecessor.
The amortized time complexity is O(1).
61.找出数组中两个只出现一次的数字
题目:一个整型数组里除了两个数字之外,其他的数字都出现了两次。
请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。
分析:这是一道很新颖的关于位运算的面试题。
ANSWER:
XOR.
62.找出链表的第一个公共结点。
题目:两个单向链表,找出它们的第一个公共结点。
链表的结点定义为:
struct ListNode
{
int m_nKey;
ListNode* m_pNext;
};
分析:这是一道微软的面试题。微软非常喜欢与链表相关的题目,
因此在微软的面试题中,链表出现的概率相当高。
ANSWER:
Have done this.
63.在字符串中删除特定的字符。
题目:输入两个字符串,从第一字符串中删除第二个字符串中所有的字符。例如,输入”They are students.”和”aeiou”, 则删除之后的第一个字符串变成”Thy r stdnts.”。
分析:这是一道微软面试题。在微软的常见面试题中,与字符串相关的题目占了很大的一部
分,因为写程序操作字符串能很好的反映我们的编程基本功。
ANSWER:
Have done this? Use a byte array / character hash to record second string. then use two pointers to shrink the 1st string.
- 寻找丑数。
题目:我们把只包含因子2、3 和5 的数称作丑数(Ugly Number)。例如6、8 都是丑数,
但14 不是,因为它包含因子7。习惯上我们把1 当做是第一个丑数。求按从小到大的顺序的第1500 个丑数。
分析:这是一道在网络上广为流传的面试题,据说google 曾经采用过这道题。
ANSWER:
TRADITIONAL.
Use heap/priority queue.
int no1500() {
int heap[4500];
heap[0] = 2; heap[1] = 3; heap[2] = 5;
int size = 3;
for (int i=1; i<1500; i++) {
int s = heap[0];
heap[0] = s2; siftDown(heap, 0, size);
heap[size] = s3; siftUp(heap, size, size+1);
heap[size+1] = s*5; siftUp(heap, size+1, size+2);
size+=2;
}
}
void siftDown(int heap[], int from, int size) {
int c = from 2 + 1;
while (c < size) {
if (c+1<size && heap[c+1] < heap[c]) c++;
if (heap[c] < heap[from]) swap(heap, c, from);
from = c; c=from2+1;
}
}
void siftUp(int heap[], int from, int size) {
while (from > 0) {
int p = (from - 1) / 2;
if (heap[p] > heap[from]) swap(heap, p, from);
from = p;
}
}
65.输出1 到最大的N 位数
题目:输入数字n,按顺序输出从1 最大的n 位10 进制数。比如输入3,则输出1、2、3 一直到最大的3 位数即999。
分析:这是一道很有意思的题目。看起来很简单,其实里面却有不少的玄机。
ANSWER:
So maybe n could exceed i32? I cannot tell where is the trick...
Who will output 2*10^9 numbers...
66.颠倒栈。
题目:用递归颠倒一个栈。例如输入栈{1, 2, 3, 4, 5},1 在栈顶。
颠倒之后的栈为{5, 4, 3, 2, 1},5 处在栈顶。
ANSWER:
Interesting...
void reverse(Stack stack) {
if (stack.size() == 1) return;
Object o = stack.pop();
reverse(stack);
putToBottom(stack, o);
}
void putToBottom(Stack stack, Object o) {
if (stack.isEmpty()) {
stack.push(o);
return;
}
Object o2 = stack.pop();
putToBottom(stack, o);
stack.push(o2);
}
67.俩个闲玩娱乐。
1.扑克牌的顺子
从扑克牌中随机抽5 张牌,判断是不是一个顺子,即这5 张牌是不是连续的。2-10 为数字本身,A 为1,J 为11,Q 为12,K 为13,而大小王可以看成任意数字。
ANSWER:
// make king = 0
boolean isStraight(int a[]) {
Arrays.sort(a);
if (a[0] > 0) return checkGaps(a, 0, 4, 0);
if (a[0] == 0 && a[1] != 0) return checkGaps(a, 1, 4, 1);
return checkGaps(a, 2, 4, 2);
}
boolean checkGaps(int []a, int s, int e, int allowGaps) {
int i=s;
while (i<e) {
allowGaps -= a[i+1] - a[i] - 1;
if (allowGaps < 0) return false;
i++;
}
return true;
}
2.n 个骰子的点数。把n 个骰子扔在地上,所有骰子朝上一面的点数之和为S。输入n,
打印出S 的所有可能的值出现的概率。
ANSWER:
All the possible values includes n to 6n. All the event number is 6^n.
For n<=S<=6n, the number of events is f(S, n)
f(S,n) = f(S-6, n-1) + f(S-5, n-1) + … + f(S-1, n-1)
number of events that all dices are 1s is only 1, and thus f(k, k) = 1, f(1-6, 1) = 1, f(x, 1)=0 where x<1 or x>6, f(m, n)=0 where m<n
Can do it in DP.
void listAllProbabilities(int n) {
int[][] f = new int[6n+1][];
for (int i=0; i<=6n; i++) {
f[i] = new int[n+1];
}
for (int i=1; i<=6; i++) {
f[i][1] = 1;
}
for (int i=1; i<=n; i++) {
f[i][i] = 1;
}
for (int i=2; i<=n; i++) {
for (int j=i+1; j<=6i; j++) {
for (int k=(j-6<i-1)?i-1:j-6; k<j-1; k++)
f[j][i] += f[k][i-1];
}
}
double p6 = Math.power(6, n);
for (int i=n; i<=6n; i++) {
System.out.println(“P(S=”+i+”)=”+((double)f[i][n] / p6));
}
}
68.把数组排成最小的数。
题目:输入一个正整数数组,将它们连接起来排成一个数,输出能排出的所有数字中最小的
一个。
例如输入数组{32, 321},则输出这两个能排成的最小数字32132。
请给出解决问题的算法,并证明该算法。
分析:这是09 年6 月份百度的一道面试题,
从这道题我们可以看出百度对应聘者在算法方面有很高的要求。
ANSWER:
Actually this problem has little to do with algorithm...
The concern is, you must figure out how to arrange to achieve a smaller figure.
The answer is, if ab < ba, then a < b, and this is a total order.
String smallestDigit(int a[]) {
Integer aux[] = new Integer[a.length];
for (int i=0; i<a.length; a++) aux[i] = a[i];
Arrays.sort(aux, new Comparator<Integer>(){
int compareTo(Integer i1, Integer i2) {
return (“”+i1+i2).compare(“”+i2+i1);
}
});
StringBuffer sb = new StringBuffer();
for (int i=0; i<aux.length, i++) {
sb.append(aux[i]);
}
return sb.toString();
}
69.旋转数组中的最小元素。
题目:把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个
排好序的数组的一个旋转,
输出旋转数组的最小元素。例如数组{3, 4, 5, 1, 2}为{1, 2, 3, 4, 5}的一个旋转,该数
组的最小值为1。
分析:这道题最直观的解法并不难。从头到尾遍历数组一次,就能找出最小的元素,时间复杂度显然是O(N)。但这个思路没有利用输入数组的特性,我们应该能找到更好的解法。
ANSWER
This is like the shifted array binary search problem. One blind point is that you may miss the part that the array is shifted by 0(or kN), that is not shifted.
int shiftedMinimum(int a[], int n) {
return helper(a, 0, n-1);
}
int helper(int a[], int s, int t) {
if (s == t || a[s] < a[t]) return a[s];
int m = s + (t-s)/2;
if (a[s]>a[m]) return helper(a, s, m);
else return helper(a, m+1, t);
}