全球彩票平台_全球彩票注册平台|官网下载地址

热门关键词: 全球彩票平台,全球彩票注册平台,全球彩官网下载地址

【全球彩票注册平台】JAVA实现链表面试题,链表

C语言非凡链表面试题分享,c语言试题共享

C语言许多面试题,这里有常用的经文面试题,应用有多样算法,如替换法,快慢指针等等。 注:含有的有关键文件引用上一篇博客单链表的插与删,本篇文章不在写出。

面试题 一:从尾到头打字与印刷单链表。

///////  1.从尾到头打印单链表 //////////

void SLitsPrintTailToHead(SListNode* pHead)//非递归算法(利用俩个指针一个定义到尾部p1,另一个定义到头开始循环p2,每当p2循环到尾部时,输出p2的值,让尾部p1指向p2.再次开始循环,以此往复。)
{

 SListNode *cur=NULL;
 while (cur!=pHead)
 {
  SListNode *tail=pHead;
  while(tail->next!=cur)
  {
   tail=tail->next;
  }
  printf("%d ",tail->data);
  cur=tail;
 }

}
void SListPrintTailToHeadR(SListNode* pHead)//递归算法
{
 if (pHead==NULL)
 {
  return;
 }
 SListPrintTailToHeadR(pHead->next);
 printf("%d ",pHead->data);
}
///////////////////////////////////////////////

面试题二:删除一个无头单链表的非尾节点(无法遍历链表)

void SListDelNonTailNode(SListNode* pos)//应用了向前替换法,把后一个的值赋值给pos替换原值,然后把pos指向pos下一个的下一个。
{
  SListNode *cur=NULL;
  cur=pos->next;
  pos->data=cur->data;
  pos->next=cur->next;
  free(cur);
}

面试题三:在无头单链表的叁个节点前插入一个节点(不可能遍历链表)

void SListInsertFrontNode(SListNode* pos, DataType x)
{
 SListNode *cur=BuySListNode(pos->data);
 cur->next=pos->next;
 pos->data=x;
 pos->next=cur;

}

面试题四:单链表达成Joseph环(JosephCircle)

///// 4.单链表实现约瑟夫环(JosephCircle) ////////////约瑟夫环就比如说一群人围成一个圈,从一个人开始报数,如报到3的人就退出,下一个继续从1开始,直到只剩一个人时结束。
SListNode* SListJosephCircle(SListNode* pHead, int k)//phead是一个循环链表 
{
 SListNode *cur=pHead;
 SListNode *nx=NULL;
 while(cur->next!=cur)
 {
  int Coun=k;
  while (--Coun)
  {
   cur=cur->next;
  }
  nx=cur->next;//利用替换法不需要遍历链表进行删除节点
  cur->data=nx->data;
  cur->next=nx->next;
  free(nx);
 }
 return cur;
}

面试题五:逆置/反转单链表

SListNode* SListReverse(SListNode* list)//逆置/反转单链表 (重要多看看)
{
 SListNode *cur=list;
 SListNode *newlist=NULL;
 SListNode *_next=NULL;
 while (cur)
 {
  _next=cur->next;
  cur->next=newlist;
  newlist=cur;
  cur=_next;
 }
 return newlist;
}

面试题六:单链表排序(冒泡排序&快捷排序)

void SListBubbleSort(SListNode* list)//单链表排序(冒泡排序&快速排序) 冒泡排序俩俩比较。
{
 SListNode *tail=NULL;
 while (list!=tail)
 {
  int change=0;
  SListNode *cur=list;
  SListNode *_next=list->next;
  while (_next!=tail)
  {
   if (cur->data > _next->data)
   {
    DataType tmp=cur->data;
    cur->data=_next->data;
    _next->data=tmp;
    change=1;
   }
   _next=_next->next;
   cur=cur->next;
  }
  if (change==0)
  {
   break;
  }
  tail=cur;
 }
}

面试题七:合併多少个静止链表,合併后还是不改变

SListNode* SListMerge(SListNode* list1, SListNode* list2)//合并两个有序链表,合并后依然有序 
{
 SListNode *newlist=NULL;//
 SListNode *list=NULL;
 if (list2==NULL)
 {
  return list1;
 }
 if (list1==NULL)
 {
  return list2;
 }
 if (list1->data < list2->data)
 {
  newlist=list=list1;//一个用来定位头,另一个用来遍历,返回时要返回头的指针才能遍历全部链表
  list1=list1->next;
 }
 else
 {
  newlist=list=list2;
  list2=list2->next;
 }
 while (list1&&list2)
 {
  if (list1->data < list2->data)
  {
   newlist->next=list1;
   list1=list1->next;
  }
  else
  {
   newlist->next=list2;
   list2=list2->next;
  }
  newlist=newlist->next;
 }
 if (list1)
 {
  newlist->next=list1;
 }
 if (list2)
 {
  newlist->next=list2;
 }
 return list;
}

面试题八:查找单链表的中等节点,供给只好遍历一遍链表

SListNode* SListFindMidNode(SListNode* list)//8.查找单链表的中间节点,要求只能遍历一次链表 
{
 SListNode *cur=NULL;//应用了快慢指针,快指针的速度是慢指针二倍,当快指针走到NULL时,慢指针所指的就是中间节点。
 SListNode *fast=NULL;
 cur=fast=list;
 while (fast && fast->next)
 {
  cur=cur->next;
  fast=fast->next->next;
 }
 return cur;
}

面试题九:查找单链表的尾数第k个节点,须要只可以遍历三次链表

SListNode* SListFindTailKNode(SListNode* list, size_t k)//9.查找单链表的倒数第k个节点,要求只能遍历一次链表 
{
 SListNode *cur,*fast;//一样用了快慢指针
 cur=fast=list;
 while(k--)
 {
  if (fast==NULL)
  {
   return 0;
  }
  fast=fast->next;
 }
 while(fast)
 {
  fast=fast->next;
  cur=cur->next;
 }
 return cur;
}

面试题十:删除链表的尾数第K个结点

void SListFindPop(SListNode *list,size_t k)//10.删除链表的倒数第K个结点 
{
 SListNode *cur=NULL;
 SListNode *tail=list;
 cur=SListFindTailKNode(list,k);
 while(list->next!=cur)
 {
  list=list->next;
 }
 list->next=cur->next;
 free(cur);
}

面试题十一:决断是或不是带环

SListNode* SListIsCycle(SListNode* list)//11.判断是否带环
{
 SListNode *cur,*fast;
 cur=fast=list;
 while (fast && fast->next)
 {
  cur=cur->next;
  fast=fast->next->next;
  if (fast==cur)
  {
   return cur;
  } 
 }
 return NULL;
}

面试题十二:求环的长短

int SListCycleLen(SListNode* meetNode)//12.求环的长度
{
 int n=1;
 SListNode *cur=meetNode;
 while(cur->next!=meetNode)
 {
    n;
  cur=cur->next;
 }
 return n;
}

面试题十三:求环的入口点(环的入口点正是一个从链表起初另一个从相遇点开,当她们相交的点便是入口点)

SListNode* SListCrossEntreNode(SListNode* list, SListNode* meetNode) //13.求环的入口点(环的入口点就是一个从链表开始另一个从相遇点开,当他们相交的点就是入口点)
{
 while (list!=meetNode)
 {
  list=list->next;
  meetNode=meetNode->next;
 }
 return list;
}

面试题十四:判定多个链表是或不是相交。(假设链表不带环)

int SListIsCrossNode(SListNode* list1, SListNode* list2)//14.判断两个链表是否相交,若相交,求交点。(假设链表不带环)
{
 while (list1 && list1->next)
 {
  list1=list1->next;
 }
 while(list2 &&list2->next)
 {
  list2=list2->next;
 }
 if (list2==list1  && list1!=NULL)
 {
  return 1;
 }
 return 0;
}

面试题十四(2):几个链表相交,求交点。

SListNode *SListEnterNode(SListNode* list1,SListNode* list2)//两个链表相交,求交点。
{
 SListNode *cur1=list1;
 SListNode *cur2=list2;
 int n1=0;
 int n2=0;
 while (cur1->next)
 {
  n1  ;
  cur1=cur1->next;
 }
 while (cur2->next)
 {
  n2  ;
  cur2=cur2->next;
 }
 cur1=list1;
 cur2=list2;
 if (n1-n2 >=0)
 {
  while (n1-n2!=0)
  {
   cur1=cur1->next;
   n1--;
  }
  while (cur1!=cur2)
  {
   cur1=cur1->next;
   cur2=cur2->next;
  }
 } 
 else
 {
  while (n2-n1!=0)
  {
   cur2=cur2->next;
   n2--;
  }
  while (cur1!=cur2)
  {
   cur1=cur1->next;
   cur2=cur2->next;
  }
 }
 return cur1;
}

全球彩票注册平台,测试代码:

void Test1()//1.从尾到头打印单链表
{ 
 SListNode *a=NULL;
 SListPushBack(&a,1);
 SListPushBack(&a,2);
 SListPushBack(&a,3);
 SListPushBack(&a,4);
 SListPushBack(&a,5);
 SListPrint(a);
 SLitsPrintTailToHead(a);//非递归 时间复杂度n平方
 SListPrintTailToHeadR(a);//递归
} 
void Test2()//2.删除一个无头单链表的非尾节点(不能遍历链表)
{
 SListNode *a=NULL;
 SListNode *pos=NULL;
 SListPushBack(&a,1);
 SListPushBack(&a,2);
 SListPushBack(&a,3);
 SListPushBack(&a,4);
 SListPushBack(&a,5);
 SListPrint(a);
 pos=SListFind(a,3);
 SListDelNonTailNode(pos);
 SListPrint(a);
}
void Test3()//3.在无头单链表的一个节点前插入一个节点(不能遍历链表)
{
 SListNode *a=NULL;
 SListNode *pos=NULL;
 SListPushBack(&a,1);
 SListPushBack(&a,2);
 SListPushBack(&a,3);
 SListPushBack(&a,4);
 SListPushBack(&a,5);
 SListPrint(a);
 pos=SListFind(a,3);
 SListInsertFrontNode(pos,8);
 SListPrint(a);
}
void Test4()//4.单链表实现约瑟夫环(JosephCircle)
{ 
 SListNode* list = NULL;
 SListNode* tail;
 SListPushBack(&list, 1);
 SListPushBack(&list, 2);
 SListPushBack(&list, 3);
 SListPushBack(&list, 4);
 SListPushBack(&list, 5);

 tail = SListFind(list, 5);
 tail->next = list;

 printf("最后的幸存者:%dn", SListJosephCircle(list, 3)->data);

}
void Test5()//5.//逆置/反转单链表
{ 
 SListNode* list = NULL;
 SListNode* newList;
 SListPushBack(&list, 1);
 SListPushBack(&list, 2);
 SListPushBack(&list, 3);
 SListPushBack(&list, 4);
 SListPushBack(&list, 5);

 newList = SListReverse(list);
 SListPrint(newList);

}
void Test6()//6.单链表排序(冒泡排序&快速排序)
{ 
 SListNode* list = NULL;
 SListPushBack(&list, 1);
 SListPushBack(&list, 22);
 SListPushBack(&list, 33);
 SListPushBack(&list, 40);
 SListPushBack(&list, 5);

 SListBubbleSort(list); 
 SListPrint(list);
}
void Test7()//7.合并两个有序链表,合并后依然有序
{ 
 SListNode *a=NULL;
 SListNode *b=NULL;
 SListNode *c=NULL;
 SListPushBack(&a,1);
 SListPushBack(&a,2);
 SListPushBack(&a,3);
 SListPushBack(&a,4);
 SListPushBack(&a,5);
 SListPushBack(&a,7);
 SListPushBack(&a,9);

 SListPushBack(&b,2);
 SListPushBack(&b,2);
 SListPushBack(&b,3);
 SListPushBack(&b,4);
 SListPushBack(&b,5);
 c=SListMerge(a,b);
 SListPrint(c);
}
void Test8()//8.查找单链表的中间节点,要求只能遍历一次链表 
{ 
 SListNode *a=NULL;
 SListNode *b=NULL;
 SListPushBack(&a,1);
 SListPushBack(&a,2);
 SListPushBack(&a,3);
 SListPushBack(&a,4);
 SListPushBack(&a,5);
 b=SListFindMidNode(a);
 SListPrint(b);
}
void Test9()//9.查找单链表的倒数第k个节点,要求只能遍历一次链表 
{ 
 SListNode *a=NULL;
 SListNode *b=NULL;
 SListPushBack(&a,1);
 SListPushBack(&a,2);
 SListPushBack(&a,3);
 SListPushBack(&a,4);
 SListPushBack(&a,5);
 b=SListFindTailKNode(a,2);
 SListPrint(b);
}
void Test10()//10.删除链表的倒数第K个结点 
{
 SListNode *a=NULL;
 SListNode *b=NULL;
 SListPushBack(&a,1);
 SListPushBack(&a,2);
 SListPushBack(&a,3);
 SListPushBack(&a,4);
 SListPushBack(&a,5);
 SListFindPop(a,3);
 SListPrint(a);
}
void Test11_12_13()//11.判断是否带环 12.求环的长度 13。求环的入口点
{
 SListNode *a=NULL;
 SListNode *enter=NULL;
 SListNode *tail=NULL;
 SListNode *cur=NULL;
 SListPushBack(&a,1);
 SListPushBack(&a,2);
 SListPushBack(&a,3);
 SListPushBack(&a,4);
 SListPushBack(&a,5);
 tail=SListFind(a,5);//构建带环
 enter=SListFind(a,3);
 tail->next=enter;
 cur=SListIsCycle(a);
 printf("是否带环:%dn",cur->data);
 printf("环长度为:%dn",SListCycleLen(cur));
 printf("环入口点为:%dn",SListCrossEntreNode(a,cur)->data);
}
void Test14()//14。判断两个链表是否相交,若相交,求交点。(假设链表不带环)
{
 SListNode *a,*b;
 SListNode *n1=BuySListNode(1);
 SListNode *n2=BuySListNode(2);
 SListNode *n3=BuySListNode(3);
 SListNode *n4=BuySListNode(4);

 a=BuySListNode(7);
 b=BuySListNode(8);
 n1->next=n2;
 n2->next=n3;
 n3->next=n4;
  a->next=b;
  b->next=n3;
  printf("是否带环:%d n",SListIsCycle(a,n1));
  printf("环的入口点为:%d n",SListEnterNode(a,n1)->data);
}

主函数:

int main()
{
 //Test1();
 //Test2();
 //Test3();
 //Test4();
 //Test5();
 //Test6();
 //Test7();
 //Test8();
 //Test9();
 //Test10();
 //Test11_12_13();
 Test14();
 system("pause");
 return 0;
}

加固一下基础,作者重新写了须臾间无头节点单链表及链表面试题。笔者会分为入门,基础,进阶三章实行计算,点击以下黄色字直接跳转对应章节。

链表难点是面试进度中有时被问到的一片段,很考察编制程序功底。近些日子刷了 LeetCode 上链表部分的面试题,作者计算了有个别有代表性的链表难题。

那份笔记整理了全副贰个星期,每一行代码都是温馨默写实现,并测验运转成功,同时也想起了刹那间《剑指offer》那本书四之日链表有关的任课,希望对笔试和面试有所协助。

加强一下基础,作者再次写了瞬间无头节点单链表及链表面试题。作者会分为入门,基础,进级三章举行总结,点击以下黄色字直接跳转对应章节。

如上正是特出面试题的解法。灵活应用,后续会持续立异。

<

C语言多数面试题,这里有常用的特出面试题,应用有两种算法,如替换法,快慢指针等等。 注...

链表及链表面试题(一)入门
链表面试题(二)基础
链表面试题(三)进级

正文使用的是 Java 语言,下边是所用到的链表节点的概念:

正文包蕴链表的以下内容:

链表及链表面试题(一)入门
链表面试题(二)基础
链表面试题(三)进级

  • 决断单链表是或不是带环?若带环,求环的长度?求环的入口点?
    3个步骤:1. 找寻换种放肆二个节点;2. 获得环中节点个数;3. 找到入口点
public class ListNode {
    int val;
    ListNode next;

    ListNode(int x) {
        val = x;
    }
}

  1、单链表的创办和遍历

链表头文件与主干落到实处在链表及链表面试题(一)入门中,此处不再赘述。

判别是不是带环 只遍历三回 时间复杂度O(n)

1. 在 O(1) 时间删除链表节点

Leetcode 237. Delete Node in a Linked List

主题材料陈述:加以单链表中需求删除的节点(不是尾节点),在 O(1) 时间删除该节点。

分析:宗旨与《编制程序之美》上的「从无头单链表中除去节点」类似。首要观念都以「狸猫换太子」,即用下三个节点数据覆盖要删减的节点,然后删除下一个节点。然而假使节点是尾节点时,该情势就没用了。

代码如下:

// 在 O(1) 时间从无头单链表中删除节点
public void deleteNode(ListNode node) {
    // 不能为空,不能为尾节点
    if (null == node || null == node.next) {
        return;
    }
    node.val = node.next.val;
    node.next = node.next.next;
}

  2、求单链表中节点的个数

  • 从尾到头打字与印刷单链表
//判断单链表是否带环?
pNode MeetNode(pList plist)
{
    assert(plist);
    pNode slow = plist;
    pNode fast = plist;

    while (fast && slow)
    {
        if (fast == slow && fast != plist)
            return slow;

        slow = slow->next;

        fast = fast->next->next;
        if(fast)
            fast = fast->next->next;
    }
    return NULL;

2. 翻盘单链表

LeetCode 206. Reverse Linked List

标题汇报:出口二个单链表的逆序反转后的链表。

分析:非递归的算法很简短,用四个不时指针 prev、cur、next 在链表上循环三次就能够。递归算法是先改变局面下一个节点,再恶化当前节点。

下边是二种算法的代码:

// 逆转单链表,循环方法
public ListNode reverseByLoop(ListNode head) {
    if (null == head || null == head.next) {
        return head;
    }
    ListNode prev = null;
    ListNode next = null;
    // 用 head 作为 cur 指针
    while (null != head) {
        next = head.next;

        head.next = prev;
        prev = head;
        head = next;
    }
    return prev;
}

// 逆转单链表,递归方法
public ListNode reverseByRecursion(ListNode head) {
    // 第一个条件判断异常,第二个条件是结束递归
    if (null == head || null == head.next) {
        return head;
    }

    ListNode newHead = reverseByRecursion(head.next);

    head.next.next = head;
    head.next = null;

    return newHead;
}

  3、查找单链表中的尾数第k个结点(剑指offer,题15)

求长度、入口点 时间复杂度小于 O(n^3)

3. 剔除单链表尾数第 n 个节点

LeetCode 19. Remove Nth Node From End of List

标题陈诉:删除单链表尾数第 n 个节点,1 <= n <= length,尽量在一回遍历中成功。

分析:拜谒难点时的首先设法是先遍历一次总结出单链表的尺寸 length,然后在遍历第三次删除第 length - n 1 个节点,然而这必要遍历四回。符合规律的去除第 n 个节点只需求遍历三遍就能够,怎样只遍历三回找到倒数第 n 个节点吧?能够设置八个指针 p1、p2,首先 p1 和 p2 都对准 head,p2 移动到第 n 个节点,然后 p1 和 p2 同不时间向后移动,当 p2 移动到终极时,p1 刚好指向最后多少个第 n 个节点。因为最终要删减尾数第 n 个节点,所以可以找到尾数第 n 1 个节点,方便删除节点。

代码如下:

// 遍历一次,删除单链表倒数第 n 个节点
public ListNode removeNthFromEnd(ListNode head, int n) {
    if (null == head) {
        return head;
    }
    ListNode p1 = head;
    ListNode p2 = head;
    // 1. p2 移动到第 n   1 个节点
    for (int i = 0; i < n; i   >) {
        p2 = p2.next;
    }
    // n == 链表长度时,p2 指向第 n   1 节点为空,倒数第 n 个节点就是头节点
    if (null == p2) {
        p1 = head.next;
        return p1;
    }
    // p1 和 p2 同时向后移动,直到 p2 到达尾节点
    while (null != p2.next) {
        p1 = p1.next;
        p2 = p2.next;
    }
    // 此时 p1 指向倒数第 n   1 个节点,删除它的下一个节点
    p1.next = p1.next.next;
    return head;
}

  4、查找单链表中的中间结点

//不改变链表结构,从尾到头打印单链表 (递归实现)
void PrintListRevers_Recursively(pList phead)
{
    if (phead)
    {
        if (phead->next)
        {
            PrintListRevers_Recursively(phead->next);
        }
        printf("%d ", phead->data);
    }
}
//若带环,求环的长度?求环的入口点?
pNode EntryNodeOfLoop(pList plist)
{
    assert(plist);
    pNode meet = MeetNode(plist);
    int i = 0;

    //求环的长度
    int count = 1;
    pNode cur = meet;
    while (meet != cur->next)
    {
        cur = cur->next;
        count  ;
    }

    //入口点
    pNode fast = plist;
    pNode slow = plist;
    for (i = 0; i < count;   i)
    {
        fast = fast->next;
    }

    while (fast != slow)
    {
        fast = fast->next;
        slow = slow->next;
    }
    return slow;
}

4. 求单链表的中等节点

标题汇报:求单链表的中间节点,假设链表的长短为偶数,重返中间四个节点的轻便三个,若为奇数,则赶回中间节点。

分析:那道题的笔触和第 3 题「删除单链表倒数第 n 个节点」很相像。如果供给只好遍历贰遍链表的花,也通过七个指针来实现。七个指针从头节点初叶,慢指针每趟向后活动一步,快指针每一回向后运动两步,直到快指针移动到尾节点时,慢指针移动到中间节点。

// 遍历一次,找出单链表的中间节点
public ListNode findMiddleNode(ListNode head) {
    if (null == head) {
        return;
    }
    ListNode slow = head;
    ListNode fast = head;
    //如果要求在单链表长度为偶数的情况下,返回中间两个节点的第一个,可以用下面的循环条件
    //while(null != fast.next && null != fast.next.next)
    while (null != fast && null != fast.next) {
        fast = fast.next.next;
        slow = slow.next;
    }
    return slow;
}

  5、合併多个静止的单链表,合并之后的链表依旧不改变【出现频率高】(剑指offer,题17)

当链表相当长的时候,递归完成的会招致函数调用层级很深,恐怕引致调用栈溢出。用栈不会晤世此类情状,分明用栈达成代码的鲁棒性会好一些。

测量检验用例

5. 论断单链表是或不是留存环

LeetCode 141. Linked List Cycle

主题材料陈说:认清多少个单链表是或不是有环

分析:照旧通过快慢指针来化解,多个指针从头节点起首,慢指针每便向后运动一步,快指针每一遍向后活动两步,假若存在环,那么七个指针一定会在环内相遇。

代码如下:

// 判断单链表是否有环
public boolean hasCycle(ListNode head) {
    if (null == head) {
        return false;
    }
    ListNode slow = head;
    ListNode fast = head;
    while (null != fast.next && null != fast.next.next) {
        fast = fast.next.next;
        slow = slow.next;
        if (fast == slow) {
            return true;
        }
    }
    return false;
}

  6、单链表的反转【出现频率最高】(剑指offer,题16)

//不改变链表结构,从尾到头打印单链表(栈实现) 
void PrintListRevers_Stack(pList phead)
{
    stack<pNode>nodes;

    pNode cur = phead;
    while (cur)
    {
        nodes.push(cur);
        cur = cur->next;
    }

    while (!nodes.empty())
    {
        cur = nodes.top();
        printf("%d ", cur->data);
        nodes.pop();
    }
}
  1. 链表中隐含环
  2. 链表中不分包环
  3. 链表有多少个或独有二个节点
  4. 空链表

6. 单链表是或不是有环扩充:找到环的入口点

LeetCode 142. Linked List Cycle II

标题陈述:推断单链表是或不是有环,借使有,找到环的入口点

分析:由上题可见,遵照 p2 每一次两步,p1 每一次一步的法门走,开采 p2 和 p1 重合,明确了单向链表有环路了。接下来,让 p2 赶回链表的底部,重新走,每回步长不是走 2 了,而是走 1,那么当 p1 和 p2 再度相见的时候,就是在环路的入口点。

借使起源到环入口的相距尾 a,p1 和 p2 首先次碰到的交接点 M 与环入口的距离为 b,环的周长为 L,当 p1 和 p2 第二遍相见时,假诺 p1 走了 n 步。其中 p1 和 p2 首先次遇上时,p1 在环内走过的步数为 b,因为当 p1 走到环入口时,p2 已经在环内了,假使此时 p2 走到环入口的步数为 c,那么 p1 再走 c 步 p2 刚好追上来和 p1 相遇,c < L,所以此时 p1 断定还没走完一圈。那么依照上边的举个例子,有下边包车型地铁涉嫌:

p1 走的门径:a b = n
p2 走的门道:a b k * L = 2n,假使此时 p2 比 p1 多走了 k 圈环路,k >= 1

依靠地方的七个等式能够得出k * L = n = a b,那么从相交点 M 发轫,p1 再走 a(a = k * L - b) 步,就一定于走了 k 圈,然后回落 b 步,注意环入口到相交点的偏离刚好为 b,所以 p1 再走 a 步时达到环入口;而 p2 从头开首走 a 的话也到达了环入口,与 p1 相遇。

而在后面这么些手续中,p1 和 p2 前 a 步走的路线分裂,再度遇到时肯定在环的入口点。

代码如下:

// 找到环的入口点
public ListNode findLoopPort(ListNode head) {
    if (null == head) {
        return null;
    }
    ListNode p1 = head;
    ListNode p2 = head;
    boolean hasCycle = false;
    // 1. 判断是否有环
    while (null != p2.next && null != p2.next.next) {
        p1 = p1.next;
        p2 = p2.next.next;
        if (p1 == p2) {
            hasCycle = true;
            break;
        }
    }
    if (!hasCycle) {
        return null;
    }

    // p2 从头开始走,步长变为 1
    p2 = head;
    while (p1 != p2) {
        p1 = p1.next;
        p2 = p2.next;
    }
    return p1;
}

  7、从尾到头打字与印刷单链表(剑指offer,题5)

  • 删去贰个无头节点单链表的非尾节点

7. 论断四个无环单链表是不是相交

主题材料汇报:交由四个无环单链表

A:       a1 → a2
                 ↘
                    c1 → c2 → c3 → null
                 ↗            
B:  b1 → b2 → b3

推断 A 和 B 是不是相交。

分析:

1.最直接的不二诀即便判别 A 链表的每一种节点是还是不是在 B 链表中,不过这种艺术的时间复杂度为 O(Length(A) * Length(B))。

2.转速为环的标题。把 B 链表接在 A 链表前面,假使获得的链表有环,则说明多个链表相交。能够事先研讨过的快慢指针来剖断是或不是有环,不过此间还会有更简便易行的法子。假如B 链表和 A 链表相交,把 B 链表接在 A 链表前面时,B 链表的有所节点都在环内,所以此时只要求遍历 B 链表,看是不是会回来起源就能够看清是或不是相交。这一个方式须求先遍历二回 A 链表,找到尾节点,然后还要遍历三次 B 链表,剖断是还是不是变成环,时间复杂度为 O(Length(A) Length(B))。

3.除了转载为环的标题,还是能选取“借使多个链表相交于某一节点,那么未来的节点都以集体全体的”这么些脾气,即使七个链表相交,那么最终一个节点肯定是集体全体的。所以能够摄取别的一种解法,先遍历 A 链表,记住尾节点,然后遍历 B 链表,比较五个链表的尾节点,借使一致则相交,分裂则不相交。时间复杂度为 O(Length(A) Length(B)),空间复杂度为 O(1),思路比解法 2 更简短。

解法 3 的代码如下:

// 判断两个无环单链表是否相交
public boolean isIntersect(ListNode headA, ListNode headB) {
    if (null == headA || null == headB) {
        return false;
    }
    if (headA == headB) {
        return true;
    }
    while (null != headA.next) {
        headA = headA.next;
    }
    while (null != headB.next) {
        headB = headB.next;
    }
    return headA == headB;
}

  8、剖断单链表是不是有环

//testMeetNode
void testMeetNode()
{
    pNode cur = NULL;
    pNode set = NULL;
    int count = 1;

    pList plist;
    InitList(&plist);

    PushBack(&plist, 1);
    PushBack(&plist, 2);
    PushBack(&plist, 3);
    PushBack(&plist, 4);
    PushBack(&plist, 5);
    PushBack(&plist, 6);
    PrintList(plist);

    //加环
    cur = plist;
    set = plist->next->next;
    while (cur->next)
        cur = cur->next;
    cur->next = set;

    pNode meetnode = MeetNode(plist);
    if (meetnode)
    {
        printf("the meet node is: %d n", meetnode->data);
        printf("the entry node of loop is: %d n", EntryNodeOfLoop(plist)->data);
    }

    else
        printf("no loop!n");

//空节点test
/*pNode meetnode = MeetNode(NULL);
    if (meetnode)
    {
        printf("the meet node is: %d n", meetnode->data);
        printf("the entry node of loop is: %d n", EntryNodeOfLoop(NULL)->data);
    }

    else
        printf("no loop!n");*/

//  DestroyList(&plist);
}

8. 两个链表相交增加:判别四个有环单链表是不是相交

题目陈诉:地点的主题材料是指向无环链表的,假若是链表有环吗?

分析:假诺多个有环单链表相交,那么它们必然共有三个环。因而得以先用在此之前快慢指针的点子找到几个链表中位居环内的四个节点,倘若相交的话,四个节点在二个环内,那么移动内部叁个节点,在一次循环内断定能够与其余一个节点相遇。

代码如下:

// 判断两个有环单链表是否相交
public boolean isisIntersectWithLoop(ListNode headA, ListNode headB) {
    if (null == headA || null == headB) {
        return false;
    }
    if (headA == headB) {
        return true;
    }
    headA = hasCycle(headA);
    headB = hasCycle(headB);
    // 没有环,则退出
    if (null == headA || headB) {
        return false;
    }

    ListNode p = headB.next;
    // p 在环内循环一次,直到与 headA 相遇
    while (p != headB) {
        if (p == headA) {
            return true;
        }
        p = p.next;
    }
    return false;
}

// 判断单链表是否有环,并返回环内的某一节点
public ListNode hasCycle(ListNode head) {
    if (null == head) {
        return null;
    }
    ListNode slow = head;
    ListNode fast = head;
    while (null != fast.next && null != fast.next.next) {
        fast = fast.next.next;
        slow = slow.next;
        if (fast == slow) {
            return slow;
        }
    }
    return null;
}

  9、抽取有环链表中,环的尺寸

void DeleteNotTailNode(pNode pos)
{
    if (pos == NULL)
        return;
    pNode tmp = pos->next;
    pos->data = tmp->data;
    pos->next = tmp->next;
    free(tmp);
    tmp = NULL;
}
  • 看清八个链表是不是相交,若相交,求交点。(就算链表** 不带环 **)

9. 四个链表相交扩张:求多个无环单链表的率先个相交点

LeetCode 160. Intersection of Two Linked Lists

主题素材陈说:找到七个无环单链表第贰个相交点,假设不相交再次回到空,供给在线性时间复杂度和常量空间复杂度内形成。

分析:

下边所说的对齐:表示指针到链表末尾的离开一样。

  1. 分成先判定是还是不是有环,再求第叁个相交点的办法。分别遍历 A 链表和 B 链表,决断它们的末梢二个节点是不是相交。然后选拔对齐的企图,总括多少个链表的长度(这些能够放在此前的遍历中做),分别用 p1 和 p2 指向五个链表的头,然后将较长链表的 p1 (假诺为 p1)向后移动 LB - LA 个节点。那样 p1 和 p2 对齐了,然后还要向后活动 p1 和 p2,直到 p1 == p2,相遇的点就是第贰个节点。

  2. 解法 第11中学为了对齐需求总括链表的长短,有未有啥方法能够不用总计链表长度呢?如果A 链表和 B 链表的长短为 LA 和 LB,若是 LB >= LA,八个指针 p1 和 p2 分别指向 A 链表和 B 链表的头节点。同有的时候候向后运动,当 p1 移动 A 链表的最后时,p2 距离 B 链表的终极的离开为 LB - LA,此时得以看看我们已经获得了长短差,怎样使用这一个尺寸差对齐吗。那时将 p1 移动到 B 链表的底部,四个指针继续移动,当 p2 移动到 B 链表的末尾时,p1 刚好运动了 LB - LA 步。此时再将 p2 移动到 A 链表的尾部,那样 p1 和 p2 就对齐了,然后继续移动,直到 p1 == p2。假如三个链表不相交,p1 和 p2 移动会同一时间活动到最终都指向空,而结识的话,第贰遍相等时正是率先个相交点。这种办法的时间复杂度为 O (2 * (Length(B))),最多要遍历一次长度较长的链表。

�解法 2 的代码如下:

// 求两个无环单链表的第一个相交点
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
    if (null == headA || null == headB) {
        return null;
    }
    if (headA == headB) {
        return headA;
    }

    ListNode p1 = headA;
    ListNode p2 = headB;
    while (p1 != p2) {
        // 遍历完所在链表后从另外一个链表再开始
        // 当 p1 和 p2 都换到另一个链表时,它们对齐了:
        // (1)如果链表相交,p1 == p2 时为第一个相交点
        // (2)如果链表不相交,p1 和 p2 同时移动到末尾,p1 = p2 = null,然后退出循环
        p1 = (null == p1) ? headB : p1.next;
        p2 = (null == p2) ? headA : p2.next;
    }
    return p1;
}

  10、单链表中,抽取环的初步点(剑指offer,题56)。本题需使用方面包车型客车第8题和第9题。

  • 在无头节点单链表的非头结点四个节点前插入二个节点

10. 总结

回过头来,会发觉上边的链表难点首要利用了「狸猫换太子」、「对齐」以及「七个指针」的方式来提升效用。在那之中使用四个指针来提供功用的方法常常使用,在碰着链表难点时得以多思索下这种思路。推荐我们记住那二种规范的链表难题,未来非常多像样的标题都得以调换来熟稔的难题再化解。

仿效文章:

  • 面试精选:链表问题总结

  11、决断多少个单链表相交的率先个交点(剑指offer,题37)

//判断两个链表是否相交,若相交,求交点。(假设链表不带环)
pNode isIntersect(pList list1, pList list2)
{
    pNode cur1 = list1;
    pNode cur2 = list2;
    int count1 = 0;
    int count2 = 0;
    int dff = 0;
    int i = 0;

    if (list1 == NULL || list2 == NULL)
        return NULL;

    while (cur1->next)
    {
        cur1 = cur1->next;
        count1  ;
    }
    while (cur2->next)
    {
        cur2 = cur2->next;
        count2  ;
    }

    dff = abs(count1 - count2);

    if (count1 > count2)
    {
        cur1 = list1;
        cur2 = list2;
        for (i = 0; i < dff; i  )
        {
            cur1 = cur1->next;
        }
        while (cur1->next && cur2->next && cur1->data != cur2->data)
        {
            cur1 = cur1->next;
            cur2 = cur2->next;
        }
    }
    else
    {
        cur1 = list1;
        cur2 = list2;
        for (i = 0; i < dff; i  )
        {
            cur2 = cur2->next;
        }
        while (cur1->next && cur2->next && cur1->data != cur2->data)
        {
            cur1 = cur1->next;
            cur2 = cur2->next;
        }
    }
    if (cur1->data == cur2->data)
        return cur1;
    else
        return NULL;
}

1、单链表的创办和遍历:

void InsertNotHeadNode(pNode pos, DataType d)
{
    assert(pos);
    pNode tmp = BuyNode(pos->data);

    tmp->next = pos->next;
    pos->next = tmp;
    pos->data = d;

}

test_isIntersect.c

 public class LinkList {
 public Node head;
 public Node current;

 //方法:向链表中添加数据
 public void add(int data) {
  //判断链表为空的时候
  if (head == null) {//如果头结点为空,说明这个链表还没有创建,那就把新的结点赋给头结点
  head = new Node(data);
  current = head;
  } else {
  //创建新的结点,放在当前节点的后面(把新的结点合链表进行关联)
  current.next = new Node(data);
  //把链表的当前索引向后移动一位
  current = current.next; //此步操作完成之后,current结点指向新添加的那个结点
  }
 }

 //方法:遍历链表(打印输出链表。方法的参数表示从节点node开始进行遍历
 public void print(Node node) {
  if (node == null) {
  return;
  }

 current = node;
  while (current != null) {
  System.out.println(current.data);
  current = current.next;
  }
 } 

 class Node {
 //注:此处的两个成员变量权限不能为private,因为private的权限是仅对本类访问。
  int data; //数据域
  Node next;//指针域

  public Node(int data) {
  this.data = data;
 }
 }


 public static void main(String[] args) {
 LinkList list = new LinkList();
 //向LinkList中添加数据
  for (int i = 0; i < 10; i  ) {
  list.add(i);
  }

  list.print(list.head);// 从head节点开始遍历输出
 }

 }
  • 单链表落成Joseph环
void test_isIntersect()
{
    pNode cur = NULL;
    pNode pos = NULL;

    pList plist1;
    pList plist2;

    InitList(&plist1);
    InitList(&plist2);

    PushBack(&plist1, 1);
    PushBack(&plist1, 3);
    PushBack(&plist1, 5);
    PushBack(&plist1, 7);
    PushBack(&plist1, 9);
    PrintList(plist1);


    PushBack(&plist2, 2);
    PushBack(&plist2, 4);
    PushBack(&plist2, 6);
    PrintList(plist2);
    //不相交

    if (pos = isIntersect(plist1, plist2))
        printf("Intersect is %dn", pos->data);
    else
        printf("not is Intersectn");

    //相交
    cur = plist2;
    while (cur->next)
        cur = cur->next;
    cur->next = plist1->next->next;
    PrintList(plist2);

    if (pos = isIntersect(plist1, plist2))
        printf("Intersect is %dn", pos->data);
    else
        printf("not is Intersectn");

}

上边代码中,那之中的Node节点选择的是在那之中类来表示(33行)。选用当中类的最大实惠是足以和表面类实行私有操作的并行拜见。

  • 看清五个链表是不是相交,若相交,求交点。(假诺链表或然** 带环 **)

注:内部类访谈的特征是:内部类能够直接访问外部类的分子,满含个人;外界类要访问内部类的积极分子,必得先成立对象。

//单链表实现约瑟夫环
pNode Joseph(pList plist, const int x)//默认从第一个开始,所以只传两个值
{
    pNode cur = plist;
    pNode head = plist;
    pNode prev = NULL;

    if (plist == NULL || x <= 0)
        return NULL;

    while (cur->next) // 成环
        cur = cur->next;
    cur->next = head;
    cur = cur->next;

    while (cur != cur->next)
    {
        int count = x;

        while (count--)
        {
            prev = cur;
            cur = cur->next;
        }
        prev->next = cur->next;
        prev->data = cur->data;
        free(cur);
        cur == NULL;
        cur = prev;
    }
    return cur;
}

为了有助于增多和遍历的操作,在LinkList类中增多贰个成员变量current,用来表示前段时间节点的目录(03行)。

  • 逆置/反转单链表
//判断两个链表是否相交,若相交,求交点。(假设链表可能带环)
pNode isIntersectL(pList list1, pList list2)
{
    pNode cur1 = list1;
    pNode cur2 = list2;
    int count1 = 0;
    int count2 = 0;
    int dff = 0;
    int i = 0;

    //判断链表是否为空
    if (list1 == NULL || list2 == NULL)
        return NULL;

    //看两条链表是否有环
    pNode pos1 = MeetNode(list1);
    pNode pos2 = MeetNode(list2);

    if (!pos1 && pos2 || pos1 && !pos2)//只有一个有环 肯定不相交
        return NULL;
    else if (pos1 && pos2) // 两个都有环
    {
        //判断是不是一个环
        Node* tmp = pos1;
        do
        {
            if (pos2 == pos1 || pos2 == pos1->next)
                break;

            pos2 = pos2->next->next;
            pos1 = pos1->next;
        } while (tmp == pos1);

        if (pos1 != pos2 && pos1->next != pos2) // 不是一个环肯定不相交
            return NULL;

        //是一个环
        while (cur1 != pos1)
        {
            cur1 = cur1->next;
            count1  ;
        }
        while (cur2 != pos1)
        {
            cur2 = cur2->next;
            count2  ;
        }

        dff = abs(count1 - count2);

        if (count1 > count2)
        {
            cur1 = list1;
            cur2 = list2;
            for (i = 0; i < dff; i  )
            {
                cur1 = cur1->next;
            }
            while (cur1->data != cur2->data)
            {
                cur1 = cur1->next;
                cur2 = cur2->next;
            }
        }
        else
        {
            cur1 = list1;
            cur2 = list2;
            for (i = 0; i < dff; i  )
            {
                cur2 = cur2->next;
            }
            while (cur1->data != cur2->data)
            {
                cur1 = cur1->next;
                cur2 = cur2->next;
            }
        }
        if (cur1->data == cur2->data)
            return cur1;
        else
            return NULL;
    }
    else // 两个都没环
        return isIntersect(list1, list2);
}

那其间的遍历链表的点子(20行)中,参数node表示从node节点开头遍历,不自然要从head节点遍历。

test_isIntersectL.c

 

//逆置链表
void ReverseList(pList* pplist)
{
    assert(pplist);
    pNode cur = *pplist;
    pNode newhead = *pplist;

    if (cur == NULL || cur->next == NULL)
        return;


    while (cur->next)
    {
        pNode tmp = cur->next;
        cur->next = tmp->next;
        tmp->next = newhead;
        newhead = tmp;
    }   
    *pplist = newhead;
}
void test_isIntersectL()
{
    pNode cur1 = NULL;
    pNode cur2 = NULL;
    pNode pos = NULL;
    pNode set = NULL;

    pList plist1;
    pList plist2;

    InitList(&plist1);
    InitList(&plist2);

    PushBack(&plist1, 1);
    PushBack(&plist1, 3);
    PushBack(&plist1, 5);
    PushBack(&plist1, 7);
    PushBack(&plist1, 9);
    //PrintList(plist1);

    PushBack(&plist2, 0);
    PushBack(&plist2, 2);
    PushBack(&plist2, 4);
    PushBack(&plist2, 6);
    //PrintList(plist2);
    //不相交

    /*if (pos = isIntersect(plist1, plist2))
        printf("Intersect is %dn", pos->data);
    else
        printf("not is Intersectn");*/

    //相交
    cur2 = plist2;
    while (cur2->next)
        cur2 = cur2->next;
    cur2->next = plist1->next->next;
    //PrintList(plist2);

    //加环
    cur1 = plist1;
    set = plist1->next->next;
    while (cur1->next)
        cur1 = cur1->next;
    cur1->next = set;

    //PrintList(plist1);
    //PrintList(plist2);

    if (pos = isIntersectL(plist1, plist2))
        printf("Intersect is %dn", pos->data);
    else
        printf("not is Intersectn");
}

2、求单链表中节点的个数:

  • 单链表排序(冒泡排序 & 迅速排序 & 选取排序)


留意检查链表是还是不是为空。时间复杂度为O(n)。那一个相比轻易。

全球彩票注册平台 1

  • 复杂链表的复制。三个链表的各类节点,有四个针对next指针指向下三个节点,还应该有二个random指针指向那一个链表中的一个随机节点还是NULL,未来要求兑现复制那几个链表,重临复制后的新链表。

主导代码:

常用排序算法时间复杂度和空中复杂度

** 复杂链表的结构 **

 //方法:获取单链表的长度
 public int getLength(Node head) {
  if (head == null) {
  return 0;
  }

  int length = 0;
  Node current = head;
  while (current != null) {
  length  ;
  current = current.next;
  }

  return length;
 }

冒泡排序的最坏时间复杂度为O(n^2)

//ps: 复杂链表的结构
struct ComplexNode
{
int _data ; // 数据
struct ComplexNode * _next; // 指向下一个节点的指针
struct ComplexNode * _random; // 指向随机节点(可以是链表中的任意节点 or 空)
};

3、查找单链表中的尾数第k个结点:

//冒泡排序
void BubbleSort(pList* pplist)
{
    assert(pplist);
    pNode p = NULL;
    pNode q = NULL;

    for (p = *pplist; p != NULL; p = p->next)
    {
        for (q = p->next; q != NULL; q = q->next)
        {
            if (p->data > q->data)
            {
                DataType tmp;
                tmp = p->data;
                p->data = q->data;
                q->data = tmp;
            }
        }
    }
}

链表及链表面试题(一)入门
链表面试题(二)基础
链表面试题(三)进级

3.1  普通思路:

神速排序是在事实上中最常用的一种排序算法,速度快,功效高。就如名字一样,火速排序是最非凡的一种排序算法。
** 急速排序采取的合计是分治观念。**

先将总体链表原原本本遍历一回,总括出链表的长度size,获得链表的尺寸之后,就好办了,直接出口第(size-k)个节点就足以了(注意链表为空,k为0,k为1,k大于链表中节点个数时的意况

  1. 先从数列中抽取贰个数作为基准数。
  2. 分区过程,将比这几个数大的数全松手它的侧边,小于或等于它的数全松开它的右侧。
  3. 再对左右距离重复第二步,直到各区间独有叁个数。
    即便快速排序的最坏时间为O(n2),但就平均质量来讲,它是依照关键字比较的里边排序算法中速度最快者,火速排序亦因而而得名。它的平分时间复杂度为O(nlgn)。

)。时间复杂度为O(n),大致思路如下:

 public int findLastNode(int index) { //index代表的是倒数第index的那个结点

  //第一次遍历,得到链表的长度size
  if (head == null) {
  return -1;
  }

  current = head;
  while (current != null) {
  size  ;
  current = current.next;
 }

  //第二次遍历,输出倒数第index个结点的数据
  current = head;
  for (int i = 0; i < size - index; i  ) {
  current = current.next;
  }

 return current.data;
 }
//快速排序
void Quicksort(pNode begin, pNode end)
{
    if (begin == NULL || end == NULL)
        return;

    DataType K = begin->data;
    pNode slow = begin;
    pNode fast = begin->next;

    if (begin != end)
    {
        while (fast != NULL)
        {
            if (fast->data < K)
            {
                slow = slow->next;

                DataType tmp = fast->data;
                fast->data = slow->data;
                slow->data = tmp;
            }
            fast = fast->next;
        }
        DataType tmp1 = slow->data;
        slow->data = begin->data;
        begin->data = tmp1;

        Quicksort(begin, slow);
        Quicksort(slow->next, end);
    }
}

假定面试官不一样意你遍历链表的长度,该怎么办啊?接下去就是。

选料排序的最坏时间复杂度为O(n^2)。
多少个要素贰个走外层pNode out三个走内层pNode in,内层元素与外层元素一点都不小小。内层先遍历,假如升序排列,碰着小的因素则将小的的值沟通到外围元素,内层走完二回后,最小的早就在最终面了,然后外层走向下一个因素,内层继续从外围的下三个因素起始遍历重复以前动作,直至外层也遍历达成,整个排序甘休。选取排序是** 动荡的排序 **艺术(比方连串[5, 5, 3]第贰次就将率先个[5]与[3]换到,导致第贰个5挪动到第贰个5背后)。

 3.2  创新思路:(这种思路在其它标题中也可能有应用)

//选择排序
void SelectionSort(pList plist)
{
    assert(plist);
    pNode out= plist;
    pNode in = NULL;

    for (; out!= NULL; out = out->next)
    {
        for (in = out->next; in != NULL; in = in ->next)
        {
            if (out->data > in ->data)
            {
                DataType tmp = out->data;
                out->data = in->data;
                in->data = tmp;
            }
        }
    }
}

     这里供给评释多个指针:即五个结点型的变量first和second,首先让first和second都指向第一个结点,然后让second结点未来挪k-1个地方,此时first和second就间隔了k-1个岗位,然后全部向后活动这多少个节点,直到second节点走到终极五个结点的时候,此时first节点所针对的职位就是倒数第k个节点的地点。时间复杂度为O(n)

  • 统一多少个静止链表,合併后依然不改变

代码完毕:(初版)

本文由全球彩票平台发布于全球彩票注册平台编程,转载请注明出处:【全球彩票注册平台】JAVA实现链表面试题,链表

TAG标签: 全球彩票平台
Ctrl+D 将本页面保存为书签,全面了解最新资讯,方便快捷。