代码改变世界

google几道面试题

  coodoing  阅读(359)  评论(0编辑  收藏  举报

1、找规律
1
1 1
2 1
1 2 1 1
1 1 1 2 2 1

下一行是什么?

2、 数列中下一个应该是: 10, 9, 60, 90, 70, 66, ?

A) 96
B) 1000000000000000000000000000000000
0000000000000000000000000000000000
000000000000000000000000000000000
C) Either of the above
D) None of the above

3、有一个特殊的链表,其中每个节点不但有指向下一个节点的指针pNext,还有一个指向链表中任意节点的指针pRand,如何拷贝这个特殊链表?    假设其对应的数据结构如下:

struct node
{
       int data;
       struct node * next;
       struct node * random;
};

如图,其中实线表示next域,虚线表示random域。

 

4、反序一个单向链表 链表数据结构如下:

class Node {
      Node* next;
}
// Return the new start after reversion.
Node* ReverseList (Node* start) { 
}

 

问题思路分析:

1、其实每一行都是对上一行的“统计”,而且去掉了汉字(如何想到的??)
第一行:“1”统计为:1个1,去掉“个”字,就变成了“11”,也就是第二行。
同理,第二行可统计为:2个1,去掉“个”字,就变成了“21”,也就是第三行。
同理,第三行可统计为:1个2和1个1,去掉“个”字和“和”字,就变成了“1211”,也就是第四行。
同理,第四行可统计为:1个1和1个2和2个1,去掉“个”字和“和”字,就变成了“111221”,也就是第五行。
同理,第五行可统计为:3个1和2个2和1个1,去掉“个”字和“和”字,就变成了“312211”,也就是第六行。

 

2、This can be looked up and found to be sequence A052196 in the On-Line Encyclopedia of Integer Sequences, which gives the largest positive integer whose English name has n letters. For example, the first few terms are ten, nine, sixty, ninety, seventy, sixty-six, ninety-six, …. A more correct sequence might be ten, nine, sixty, googol, seventy, sixty-six, ninety-six, googolplex. And also note, incidentally, that the correct spelling of the mathematical term “google” differs from the name of the company that made up this aptitude test。so the answer of this problem is (A)

 

3、分析思路可参考:http://blog.sina.com.cn/s/blog_411fed0c0100rrj5.html。 拷贝pNext指针非常容易,所以题目的难点是如何拷贝pRand指针。 一种思路:如果不允许修改L的值,用哈希函数,先依次遍历原链表,每经过一个节点X,开辟一个新节点Y,然后(key=X的地址,value=Y的地址)存入哈希表。第二次再遍历原链表,根据拓扑结构设置新的链表。需要O(n)的空间。另外一种思路:
         假设原来链表为A1 -> A2 ->... -> An,新拷贝链表是B1 -> B2 ->...-> Bn。 为了能够快速的找到pRand指向的节点,并把对应的关系拷贝到B中。我们可以将两个链表合并成 A1 -> B1 -> A2 -> B2 -> ... -> An -> Bn。 从A1节点出发,很容易找到A1的pRand指向的节点Ax,然后也就找到了Bx,将B1的pRand指向Bx也就完成了B1节点pRand的拷贝;依次类推。 当所有节点的pRand都拷贝完成后,再将合并链表分成两个链表就可以了

  • 首先在遍历原来链表的过程中,插入新的节点,比如A_N是拷贝(A_O)的,同时进行操作:(链表插入操作

            A_N->next = A_O->next;

            A_O->next = A_N;

             通过一个遍历,我们就可以将链表复制成下图中的样子。

  • 在完成next域的链接后,需要开始做random域的复制。  在实现了next的结构之后,我们需要开始对new_list的random域进行赋值。那么有:

         A_N->random = A_O->random->next;

       如上图所示:A_O->random为C_O,C_O的next为C_N,这样A_N->random = C_N。

  • 最后再声明一个temp指针,恢复原先链表的next,同时copy到新链表的next。

temp = A_O->next;

A_O->next = temp->next;

temp = temp->next->next;
对于 temp->next = temp->next->next,即B_N。

     该算法复杂度为O(N),空间复杂度为O(1),除了新拷贝的空间之外没有额外地址。

    具体代码如下:

   1: typedef struct __Node
   2: {
   3:     int nData;
   4:     __Node* pNext;
   5:     __Node* pRandom;
   6: } Node;
   7: Node* DuplicateList(Node* pSrcListHead)
   8: {
   9:     if (pSrcListHead == NULL)
  10:         return NULL;
  11:  
  12:     Node* pNode = pSrcListHead;
  13:     // 首先拷贝next域
  14:     while (pNode != NULL)
  15:     {
  16:         Node* pNewNode = new Node;
  17:         pNewNode->nData = pNode->nData;
  18:         pNewNode->pNext = pNode->pNext;        
  19:         pNode->pNext = pNewNode;
  20:         //pNewNode->pRandom = pNode->pRandom;
  21:  
  22:         pNode = pNewNode->pNext; // 递归遍历
  23:     }
  24:  
  25:     Node* pDestListHead = pSrcListHead->pNext;
  26:     pNode = pSrcListHead;
  27:      // 完成random域
  28:     while (pNode != NULL)
  29:     {
  30:         pNode->pNext->pRandom = pNode->pRandom->pNext;
  31:         pNode = pNode->pNext->pNext;
  32:     }
  33:     
  34:     pNode = pSrcListHead;
  35:     Node* pNode2 = pNode->pNext;
  36:     while (pNode != NULL)
  37:     {
  38:         pNode->pNext = pNode2->pNext;
  39:         pNode = pNode->pNext;
  40:         if (pNode)
  41:             pNode2->pNext = pNode->pNext;
  42:         else
  43:             pNode2->pNext = NULL;
  44:         pNode2 = pNode2->pNext;
  45:     }
  46:     return pDestListHead;
  47: }

4、定义两个辅助指针,一个指向当前结点,设为cur;一个指向前一个结点,设为prev,然后反转 cur->next = prev。但是原来的cur->next丢失了。可以再定义一个辅助指针temp,用来保存这个值。另外就是一些为空的判断,需要加倍小心

Node* reverseNode(Node* p)
{

        Node *prev= NULL;
        Node *cur= p;

    //开始反转
    while(cur!= NULL)
    {
        Node *temp= cur->next; //临时保存下一个结点,为了循环遍历的需要

        
        //关键的三步
        cur->next = prev;  //反转操作
        prev= cur;        //prev指针移动

        cur= temp;       //更新当前结点
    }
    return pPre;  //pPre变为第一个结点

}

更多参考资料:

http://coolshell.cn/articles/3345.html

http://zhedahht.blog.163.com/blog/static/254111742010819104710337/

编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 25岁的心里话
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示