题目

原文:

Given a circular linked list, implement an algorithm which returns node at the beginning of the loop.

DEFINITION

Circular linked list: A (corrupt) linked list in which a node’s next pointer points to an earlier node, so as to make a loop in the linked list.

EXAMPLE

Input: A –> B –> C –> D –> E –> C [the same C as earlier]

Output: C

译文:

给定一个循环链表,实现一个算法返回这个环的开始结点。

定义:

循环链表:链表中一个结点的指针指向先前已经出现的结点,导致链表中出现环。

例子:

输入:A –> B –> C –> D –> E –> C [结点C在之前已经出现过]

输出:结点C

解答

关于带环链表的题目,《编程之美》中也有讲过。方法很tricky,设置快慢指针, (快指针速度为2,慢指针速度为1)使它们沿着链表移动,如果这个链表中存在环, 那么快指针最终会追上慢指针而指向同一个结点。接下来的问题是,快指针追上慢指针后, 怎么找到这个环的开始结点? 现在我们还没有答案,那让我们先来分析一下,快指针会在哪里追上慢指针。

无图无真相,先上图:

设环的开始结点(图中的D)前有k个结点,环有n个结点(上图中n从D到K共8个结点)。 快指针fast和慢指针slow一开始都指向头结点head,它们移动k步可到环的开始结点。 假设慢指针走过m个结点后,快指针追上了它,这时快指针走过了2m个结点。 快指针比慢指针多走过的结点都在环里转圈了,是环中结点数n的整数倍,即:

2m - m = pn --> m = pn, p为正整数

如果头结点是第一个结点的话,那么相遇结点就是第m+1=pn+1个结点。减去环之前的k 个结点,得到从环开始结点到相遇结点的结点数pn+1-k。相遇结点需要再经过 n-(pn+1-k)+1=(1-p)n+k个结点,才能回到环的开始结点(图中结点D)。 如果让快指针在相遇结点继续走,不过这次把速度变成了慢指针一样, 那么它要走(1-p)n+k步到达环开始结点,让慢指针从头结点head开始走, 它要走k步到达环开始结点。最后,它们将在环开始结点处相遇。

这个是怎么得出来的呢?假设快指针走了(1-p)n+k个结点到达环的开始结点,这时, 慢指针也走了(1-p)n+k步,它离环的开始结点还有

k - [ (-p)n + k ] = (p-)n (步)

而这正好是环中结点数的整数倍,所以当慢指针到达环的开始结点时, 快指针(此时它的速度也是1)刚好在环中转了(p-1)圈,然后和慢指针在环的开始结点处相遇。

代码如下:

node* loopstart(node *head){
if(head==NULL) return NULL;
node *fast = head, *slow = head;
while(fast->next!=NULL){
fast = fast->next->next;
slow = slow->next;
if(fast==slow) break;
}
if(fast->next==NULL) return NULL;
slow = head;
while(fast!=slow){
fast = fast->next;
slow = slow->next;
}
return fast;
}

这个思路确实很巧很tricky。但,还有没有别的方法呢?更直观更简单的方法。 既然这么问了,当然是有了。:p一个无环的链表,它每个结点的地址都是不一样的。 但如果有环,指针沿着链表移动,那这个指针最终会指向一个已经出现过的地址。 答案是不是已经呼之欲出了。嗯,没错,哈希表!

以地址为哈希表的键值,每出现一个地址,就将该键值对应的实值置为true。 那么当某个键值对应的实值已经为true时,说明这个地址之前已经出现过了, 直接返回它就OK了。

由于C++标准中没有哈希表的操作,我用map进行模拟。不过哈希表的插入和取值操作是O(1) 的时间。而map是由一个RB tree组织,为了维护这个RB tree,插入和取值都会花更多的时 间。

代码如下:

map<node*, bool> hash;
node* loopstart1(node *head){
while(head){
if(hash[head]) return head;
else{
hash[head] = true;
head = head->next;
}
}
return head;
}

完整代码如下:

#include <iostream>
#include <map>
using namespace std; typedef struct node{
int data;
node *next;
}node; node* init(int a[], int n, int m){
node *head, *p, *q;
for(int i=; i<n; ++i){
node *nd = new node();
nd->data = a[i];
if(i==m) q = nd;
if(i==){
head = p = nd;
continue;
}
p->next = nd;
p = nd;
}
p->next = q;
return head;
} node* loopstart(node *head){
if(head==NULL) return NULL;
node *fast = head, *slow = head;
while(fast->next!=NULL){
fast = fast->next->next;
slow = slow->next;
if(fast==slow) break;
}
if(fast->next==NULL) return NULL;
slow = head;
while(fast!=slow){
fast = fast->next;
slow = slow->next;
}
return fast;
} map<node*, bool> hash;
node* loopstart1(node *head){
while(head){
if(hash[head]) return head;
else{
hash[head] = true;
head = head->next;
}
}
return head;
}
int main(){
int n = , m = ;// m<n
int a[] = {
, , , , , , , , ,
};
node *head = init(a, n, m);
//node *p = loopstart(head);
node *p = loopstart1(head);
if(p)
cout<<p->data<<endl;
return ;
}

Cracking the coding interview--Q2.5的更多相关文章

  1. Cracking the coding interview

    写在开头 最近忙于论文的开题等工作,还有阿里的实习笔试,被虐的还行,说还行是因为自己的水平或者说是自己准备的还没有达到他们所需要人才的水平,所以就想找一本面试的书<Cracking the co ...

  2. Cracking the coding interview 第一章问题及解答

    Cracking the coding interview 第一章问题及解答 不管是不是要挪地方,面试题具有很好的联系代码总用,参加新工作的半年里,做的大多是探索性的工作,反而代码写得少了,不高兴,最 ...

  3. Cracking the Coding Interview(Trees and Graphs)

    Cracking the Coding Interview(Trees and Graphs) 树和图的训练平时相对很少,还是要加强训练一些树和图的基础算法.自己对树节点的设计应该不是很合理,多多少少 ...

  4. Cracking the Coding Interview(Stacks and Queues)

    Cracking the Coding Interview(Stacks and Queues) 1.Describe how you could use a single array to impl ...

  5. 《Cracking the Coding Interview》读书笔记

    <Cracking the Coding Interview>是适合硅谷技术面试的一本面试指南,因为题目分类清晰,风格比较靠谱,所以广受推崇. 以下是我的读书笔记,基本都是每章的课后习题解 ...

  6. Cracking the coding interview目录及资料收集

    前言 <Cracking the coding interview>是一本被许多人极力推荐的程序员面试书籍, 详情可见:http://www.careercup.com/book. 第六版 ...

  7. 《Cracking the Coding Interview》——第13章:C和C++——题目6

    2014-04-25 20:07 题目:为什么基类的析构函数必须声明为虚函数? 解法:不是必须,而是应该,这是种规范.对于基类中执行的一些动态资源分配,如果基类的析构函数不是虚函数,那么 派生类的析构 ...

  8. 《Cracking the Coding Interview》——第5章:位操作——题目7

    2014-03-19 06:27 题目:有一个数组里包含了0~n中除了某个整数m之外的所有整数,你要设法找出这个m.限制条件为每次你只能用O(1)的时间访问第i个元素的第j位二进制位. 解法:0~n的 ...

  9. 二刷Cracking the Coding Interview(CC150第五版)

    第18章---高度难题 1,-------另类加法.实现加法. 另类加法 参与人数:327时间限制:3秒空间限制:32768K 算法知识视频讲解 题目描述 请编写一个函数,将两个数字相加.不得使用+或 ...

  10. 《Cracking the Coding Interview 》之 二叉树的创建 与 遍历(非递归+递归version)

    #include <iostream> #include <cstdio> #include <vector> #include <stack> #de ...

随机推荐

  1. OpenStack+Ceph存储空间回收《转》

    转自:http://blog.csdn.net/wytdahu/article/details/48288681 问题描述 在OpenStack云环境的部署中,存储通常具备Thin provision ...

  2. 手机网络抓包 转载记录http://blog.csdn.net/skylin19840101/article/details/43485911

    Fiddler不但能截获各种浏览器发出的HTTP请求, 也可以截获各种智能手机发出的HTTP/HTTPS请求.Fiddler能捕获IOS设备发出的请求,比如IPhone, IPad, MacBook. ...

  3. GL_总账会计科目追寻SLA及子模组

    相信做总账的学友们,一般很多时间都会花费在查询日记账的来源,因为R12多了一个SLA模组,又有些增加了追溯日记账的难度,个人整理了一下 11i过账方式: 子模组-> 总账 (Post Journ ...

  4. LevelDB场景分析2--Open

    1.源码 1 Status DB::Open(const Options& options, const std::string& dbname,      uint64_t new_ ...

  5. ZOJ 1654 Place the Robots建图思维(分块思想)+二分匹配

    题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=654 AC一百道水题,不如AC一道难题来的舒服. 题意:一个n*m地图 ...

  6. 关于阿里云centos 2.6下手机表情输入后无法保存到mysql数据库的问题调研及mysql版本从5.1升级到5.7的全过程纪要

    近日在开发手机app的评论功能时,输入表情文字,保存后提示数据库保存失败.错误日志片段如下 caused by: java.sql.SQLException: Incorrect string val ...

  7. 获取Android运行apk的packagename 和activityname

    自动化测试中经常遇到这个问题,关于这个题目,方法众多,咱的目的是找个比较简单靠谱的: 方法一: 先进入cmd窗口,adb shell 后: cd /data/data ls 可以看到包名了吧,缺点很明 ...

  8. 利用eChart绘制网页图表

    首先,最好的教程在这里:eCchart eChart所需JS: echarts.min.js china.js echarts.js 页面代码如下: 一.图表 <!DOCTYPE html> ...

  9. Mac 下的矢量图设计工具

    Mac 下的矢量图设计工具 一图胜千言.一张清晰的示意图无论对于系统设计,流程梳理,还是其他的方方面面,都非常重要. 曾经亲见一位老同事把 FreeHand 这个矢量绘图工具用得出神入化,并且非常成功 ...

  10. Xilinx IP核的根目录地址,有datasheet 和仿真相关的资料

    C:\Xilinx\14.7\ISE_DS\ISE\coregen\ip\xilinx\dsp\com\xilinx\ip Xilinx IP核的根目录地址,有datasheet 和仿真相关的资料