数据结构之链表经典算法QJ题目

单链表经典算法题目

1. 单链表相关经典算法OJ题:移除链表元素

题目路径(点击练习):

题目:
在这里插入图片描述

思路一:

遍历原链表,遇到val就执行删除val节点的操作

在这里插入图片描述

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* removeElements(struct ListNode* head, int val) {
    
		//当链表的头结点的值为val时
       while(head && head->val==val)
    {
        head = head->next;
    }
    //当链表为空的时候,直接返回
     if (head == NULL) {
        return head;
    }   
      
    struct ListNode* pre = head;//定义临时指针指向与head一致

   
     while (pre->next)
    {
    	 //当链表指向的下一个节点的值为val
        if (pre->next->val == val) {
            pre->next = pre->next->next;   
        } else {
            /* 没找到,则继续遍历查找 */
            pre = pre->next;
        }
    }
    return head;
}



思路二:

定义新链表,遍历原链表找不为val的节点,尾插在新链表中

在这里插入图片描述

链表为空:插入进来的节点就是链表的头结点和尾结点

链表不为空:插入进来的节点就是新的尾结点

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */


struct ListNode* removeElements(struct ListNode* head, int val) {
    struct ListNode* newHead = NULL;
    struct ListNode* newtail = NULL;
    struct ListNode* pcur = head;

    while(pcur)
    {
        //当原链表pcur的val不为查找的val时,将此节点尾插到新节点中,否则就继续往下走
        if(pcur->val != val)
        {
            //当链表为空
            if(newHead == NULL)
            {
                newHead = newtail = pcur;
            }else{
                //链表不为空
                newtail->next = pcur;
                newtail = newtail->next;
            }
        }
        pcur = pcur->next;
    }

    if(newtail)
        {
            newtail->next=NULL;
        }
    return newHead;
}

2. 单链表相关经典算法QI题:链表的中间节点

题目路径(点击练习)

题目

在这里插入图片描述

思路一

使用循环遍历统计链表中的个数

使用for循环根据除以2结果走到中间节点

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* middleNode(struct ListNode* head) {
    struct ListNode* pre= head;
    int flag = 0;//用于计数
    while(pre)
    {
        flag++;//统计链表的个数
        pre=pre->next;
    }
    
   int mid = flag/2;//获取中间的位置
   pre=head;
   for(int i=0;i<mid;i++)
   {
       pre=pre->next;
   }
    return pre;
}
思路二

根据快慢指针

先定义两个指针
slow指针每走一步
fast指针每走两步

当fast->next 为空,则slow刚好指向的就是中间节点

在这里插入图片描述

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* middleNode(struct ListNode* head) {  
    //定义两个指针
    struct ListNode* slow = head;
    struct ListNode* fast = head;

    while(fast&&fast->next)
    {
        slow = slow->next;//一次走一步
        fast = fast->next->next;//一次走两步。当fase走完的时候slow指向的就是中间的节点
    }
    return slow;
}

3. 单链表相关经典算法QJ题:反转链表

题目路径(点击练习)

题目:

在这里插入图片描述

思路一

简单迭代

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* reverseList(struct ListNode* head) {
   //定义两个指针
   struct ListNode* temp = NULL;
   struct ListNode* curr = NULL;
   //循环遍历head
    while(head){
        temp = head->next;
        head->next = curr;
        curr = head;
        head = temp;//head和temp已被事实上置空了,防止跑飞
    }
    return curr;

}
思路二

创建三个指针

分别记录前驱结点,当前节点,后继节点,改变原链表指针方向
在这里插入图片描述

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* reverseList(struct ListNode* head) {
    //处理空链表
    if(head==NULL)
    {
        return head;
    }
    
    //创建三个指针,分别记录前驱节点,当前节点以及后继节点
    struct ListNode* n1 = NULL;
    struct ListNode* n2 = head;
    struct ListNode* n3 = head->next;

    while(n2)
    {
        n2->next = n1;

        n1 = n2;
        n2 = n3;
        if(n3)
        {
            n3 = n3->next;
        }
    }
 return n1;
}

4. 单链表相关经典算法QJ题:合并两个有序链表

题目路径(点击练习)

题目

在这里插入图片描述

思路

在两个原链表中创建两个指针l1,l2
再创建一个新链表

l1和l2相比较,较小值的放入新链表中
在这里插入图片描述

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {

    //当list1为空时直接返回list2
   if(list1 == NULL)
   {
       return list2;
   }
   //同理
   if(list2 == NULL)
   {
       return list1;
   }

   struct ListNode* l1 = list1;
   struct ListNode* l2 = list2;

   struct ListNode* newHead = NULL;
   struct ListNode* newTail = NULL;


   while(l1 && l2)
   {
       //当l1<l2
       if(l1->val < l2->val)
       {
           //判读链表是否为空
           if(newHead == NULL)
           {
               newHead = newTail = l1;
           }else{
               newTail->next = l1;
               newTail = newTail->next;
           }
           l1 = l1->next;
       }//l2<l1
       else{
           if(newHead == NULL)
           {
               newHead = newTail = l2;
           }else{
               newTail->next = l2;
               newTail = newTail->next;
           }
           l2=l2->next;
       }
       
   }
      //跳出循环时,出现两种情况l1为空,或者l2为空
      if(l1)
      {
          newTail->next = l1;
      }
      if(l2)
      {
          newTail->next = l2;
      }

   return newHead;
}

但是我们可以看到,上述出现了重复的代码,如何优化解决呢?

在这里插入图片描述

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
 typedef struct ListNode ListNode;
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {

    //当list1为空时直接返回list2
   if(list1 == NULL)
   {
       return list2;
   }
   //同理
   if(list2 == NULL)
   {
       return list1;
   }

    ListNode* l1 = list1;
    ListNode* l2 = list2;

   ListNode* newHead,*newTail;//申请一块哨兵位
   newHead=newTail=(ListNode*)malloc(sizeof(ListNode));
   while(l1 && l2)
   {
       //当l1<l2
       if(l1->val < l2->val)
       {
           newTail->next = l1;
           newTail = newTail->next;
           l1 = l1->next;
       }//l2<l1
       else{
           newTail->next = l2;
           newTail = newTail->next;
           l2=l2->next;
       }
       
   }
      //跳出循环时,出现两种情况l1为空,或者l2为空
      if(l1)
      {
          newTail->next = l1;
      }
      if(l2)
      {
          newTail->next = l2;
      }

      
    //malloc开辟了空间,但是这块空间用不了得释放掉
    ListNode* ret = newHead->next;
    free(newHead);  

   return ret;
}

5. 循环链表经典应用:环形链表的约瑟夫问题

著名的Josephus问题 据说著名犹太 Josephus有过以下的故事:
~
在罗⻢⼈占领乔塔帕特后,39 个犹太⼈与Josephus及他的朋友躲到⼀个洞中,39个犹太⼈决定宁愿死也不要被⼈抓到,于是决定了⼀个⾃杀 ⽅式,41个⼈排成⼀个圆圈,由第1个⼈开始报数,每报数到第3⼈该⼈就必须⾃杀,然后再由下⼀ 个重新报数,直到所有⼈都⾃杀⾝亡为⽌。 历史学家
然⽽Josephus 和他的朋友并不想遵从,Josephus要他的朋友先假装遵从,他将朋友与⾃⼰安排在 第16个与第31个位置,于是逃过了这场死亡游戏。

题目

题目路径(点击练习)

在这里插入图片描述

思路

根据n来创建不带头单向链表
逢m删除当前节点

在这里插入图片描述

/**
 * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
 *
 * 
 * @param n int整型 
 * @param m int整型 
 * @return int整型
 */

 typedef struct ListNode ListNode;

 ListNode* BuyNode(int x)
 {
    ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));
    newnode->val = x;
    newnode->next = NULL;
    return newnode;
 }

 ListNode* createList(int n)
 {
    ListNode* phead = BuyNode(1);
    ListNode* ptail = phead;
    for(int i = 2;i<=n;i++)
    {
        ptail->next=BuyNode(i);
        ptail = ptail->next;
    }
    //链表要首尾相连使其循环起来
    ptail->next = phead;
    return phead;
 }
int ysf(int n, int m ) {
    //根据n来创建不带头单向链表
    ListNode* head = createList(n);
    ListNode* pcur = head;
    ListNode* prev = NULL;
    int count = 1;
    //逢m删除当前节点
    while(pcur->next != pcur)
    {
       if(count == m)
       {
        //删除当前节点
        prev->next = pcur->next;
        free(pcur);
        pcur = prev->next;
        count = 1;

       }else{
        prev = pcur;
        pcur = pcur->next;
        count++;
       }
    }
    //此时,节点便是唯一幸存下来的
    return pcur->val;
}

6. 单链表相关经典算法 QJ题:分割链表

题目路径(点击练习)

题目

在这里插入图片描述

思路

定义两个链表:大链表和小链表,遍历原来的节点将其放入对应的新链表中,最后将大链表和小链表的首尾相连

在这里插入图片描述

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */

typedef struct ListNode ListNode;
struct ListNode* partition(struct ListNode* head, int x){
    //小链表
    ListNode* lessHead,*lessTail;
    lessHead = lessTail = (ListNode*)malloc(sizeof(ListNode));//创建哨兵位

    //大链表
    ListNode* greaterHead,*greaterTail;
    greaterHead = greaterTail = (ListNode*)malloc(sizeof(ListNode));//创建哨兵位

    ListNode* pcur = head;

    while(pcur)
    {
        if(pcur->val < x)
        {
            lessTail->next = pcur;
            lessTail = lessTail->next;
        }else{
            greaterTail->next = pcur;
            greaterTail = greaterTail->next;
        }
        pcur = pcur->next;
    }
    
    greaterTail->next = NULL;
    lessTail->next = greaterHead->next;

    ListNode* ret = lessHead->next;
    free(lessHead);
    free(greaterHead);
    return ret;
}

  • 23
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值