面试题2(循环链表)

     题目为:对于普通的单向链表,如果实现确定其内部有一个环,如何确定何处出现环路的?单向链表每个节点中只有data和next两个字段。

 

      (单向链表含环路,不要总是想到“0”型环路,还要想到“6”字型环路)

      原本听到这道题时,我首先想到的笨办法就是:建一个足够大的一维数组,,每个位置放Node*类型指针。而后开始遍历单向链表,遍历过一个节点后就将该节点的指针添加到这个一维数组中,随后与该数组前边的所有元素进行一次遍历比较,如果有重复,则定位到了这个出现环路的节点。

      但是后来面试官说:这个空间复杂度有点大,如果场景是有几百万条记录呢?有没有办法大大的降低这个时间复杂度?    因为是电面的,自己一时也没想出什么好办法来,惭愧惭愧~今天一早请教了下龙哥,龙哥给出了一个不错的思路,我测了一下,没有问题。

 

      主体思路是:

      从头结点开始遍历整个链表,没遍历过一个节点:就将其next置为NULL.这样:当往后遍历到某个节点:其next指向节点的next为NULL时变找到了。 注意:①很多人看到后会说:你这样不是破坏了原先的单向链表了吗?的确是这样,所以在考虑这种算法时还要同时考虑该如何进行恢复!最好是:使用完了之后接着恢复。而要做到这一点只能用递归来实现。(不过用递归貌似还是很大空间复杂度)

    struct Node { int data; int pNext; }; void Fun(Node* pData,int currentPos,int& callbackPos) { if(pData[currentPos].pNext) { int backup = pData[currentPos].pNext; pData[currentPos].pNext = NULL; Fun(pData,backup,callbackPos); pData[currentPos].pNext = backup; } else { callbackPos = currentPos; } } int main() { //initilze array: Node* pData = new Node[7]; for(int i=0;i<6;i++) { pData[i].pNext = i+1; } pData[6].pNext = 3; for(int i=0;i<7;i++) { pData[i].data = 10; } //----------------------- int callback = -1; Fun(pData,0,callback); printf("%d/n", callback); system("pause"); return 0; }

 

    所以:有时候递归用来处理这种既需要全局变化,又需要恢复的算法时很有用。

你可能感兴趣的:(算法,面试,struct,System,callback,fun)