数据结构算法题:链表算法题

文章目录

  • 链表算法题目
    • 单链表反转
      • 递归解法
        • 解题图解
        • 代码实现
    • 链表中环的检测并找到环的入口
      • 快慢指针法
        • 解题图解
        • 环检查的代码实现
        • 找到环的入口代码实现
    • 两个有序链表的合并
      • 申请一个新的链表的解题思路
        • 解题思路
        • 代码实现
    • 删除链表倒数第N个节点
      • 一次遍历解法
        • 解题图解
        • 代码实现
    • 求链表的中间节点
      • 快慢指针解法
        • 解题图解
        • 代码实现

链表算法题目

单链表反转

递归解法

解题图解

  1. 使用递归遍历到最后一个节点
  2. 返回到上一个节点完成:将数据下一个节点指向自己、自己的Next指向NULL, 将new_head返回到上一个节点。
    数据结构算法题:链表算法题_第1张图片
    数据结构算法题:链表算法题_第2张图片
    数据结构算法题:链表算法题_第3张图片
    数据结构算法题:链表算法题_第4张图片
    数据结构算法题:链表算法题_第5张图片

代码实现

测试地址

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* reverseList(ListNode* head) {
      if( head == NULL || head->next == NULL )
         return head;
      else{
         ListNode *new_head = reverseList(head->next);
         head->next->next = head;
         head->next = NULL;
         return new_head;
      }
    }
};

链表中环的检测并找到环的入口

快慢指针法

解题图解

是否有环:
申请两个指针一个每一次走两步,另一个每一次走一步,如果快指针的next为null,则表明没有环。
环的入口:
数据结构算法题:链表算法题_第6张图片
如图所示,快慢指针在距离环起点w的位置相遇,那说明快指针比慢指针多走了几个环(设为kn,n表示环的长度,k=1、2、3……),假设一共走了x步才相遇,那可以得到如下的公式:

2x = x + k*n (k=1、2、3……)

有以上公式看到相遇点走的步数一定是环长度的k倍才可以相遇,即:

x = k*n;

还可以知道:

x = t + w

由此可以推到:

k*n = t + w
t = k*n - w

有t = k*n - w可以知道的,让一个指针在开始出,另外一个指针在w处,同时以相同的步幅移动,最后会在入口点相遇。

环检查的代码实现

leetcode测试地址

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    bool hasCycle(ListNode *head) {
        if (head == NULL)
          return false; 
        ListNode *slow_ptr = head;
        ListNode *fast_ptr = head;
        bool bool_loop = false;
        while ( fast_ptr != NULL && fast_ptr->next != NULL && fast_ptr->next->next != NULL)
        {
            fast_ptr = fast_ptr->next->next;
            slow_ptr = slow_ptr->next;
            if ( fast_ptr == slow_ptr)   //这里比较两个指针是否相等,应为val可能有相同的值
            {
                bool_loop = true;
                break;
            }
                
        }
        
        return bool_loop;
    
    }
};

找到环的入口代码实现

leetcode测试地址

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
                if (head == NULL)
          return NULL; 
        ListNode *slow_ptr = head;
        ListNode *fast_ptr = head;
        bool bool_loop = false;
        while ( fast_ptr != NULL && fast_ptr->next != NULL && fast_ptr->next->next != NULL)
        {
            fast_ptr = fast_ptr->next->next;
            slow_ptr = slow_ptr->next;
            if ( fast_ptr == slow_ptr )
            {
                bool_loop = true;
                break;
            }
                
        }
        
        if (!bool_loop)
            return NULL;
        
        ListNode *tmp_ptr = head;
        while ( tmp_ptr != slow_ptr )  // //这里比较两个指针是否相等,应为val可能有相同的值
        {
            tmp_ptr = tmp_ptr->next;
            slow_ptr = slow_ptr->next;
        }
        
        return tmp_ptr;
    }
};

两个有序链表的合并

申请一个新的链表的解题思路

解题思路

申请一个新的链表,第一个为哨兵节点,这样可以将边界的解法和正常情况统一起来。之后比较l1和l2,谁小谁放到新的里面。终止条件是有一个链表先为空了。

代码实现

leetcode测试地址

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
        ListNode* guard = new ListNode(0);
        ListNode* guard_new =guard;
        
        while( l1!=NULL && l2!=NULL)
        {
            if( l1->val < l2->val )
            {
                guard->next = l1;
                l1=l1->next;
                guard = guard->next;
            }else{
                guard->next = l2;
                l2 = l2->next;
                guard = guard->next;
            }
        }
        
        if( l1 != NULL )
        {
            guard->next = l1;
        }else{
            guard->next = l2;
        }
        
        return guard_new->next;
    }
};

删除链表倒数第N个节点

一次遍历解法

解题图解

首先在头部增加一个哨兵节点,可以有效解决一个节点和两个节点的边界问题。申请了两个指针first和second,先让first和second相差n+1和位置(n+1位置是因为删除n时需要让second指向n-1的节点)。之后让first和second保持相同的幅度移动直到first==null。
数据结构算法题:链表算法题_第7张图片
数据结构算法题:链表算法题_第8张图片
数据结构算法题:链表算法题_第9张图片

代码实现

leetcode代码测试地址

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode* guard = new ListNode(0);
        guard->next=head;
        
        ListNode* first_ptr=guard;
        ListNode* slow_ptr=guard;
        
        int i=1;
        for(i=1; i<=n+1; i++)
            first_ptr=first_ptr->next;
        while(first_ptr != NULL)
        {
            slow_ptr=slow_ptr->next;
            first_ptr=first_ptr->next;
        }
        
        slow_ptr->next=slow_ptr->next->next;
        return guard->next;
    }
};

求链表的中间节点

快慢指针解法

解题图解

分成两种情况,一种是奇数的情况,退出的条件是f->next == NULL。
数据结构算法题:链表算法题_第10张图片
一种是偶数的情况,退出的条件是f == NULL。
数据结构算法题:链表算法题_第11张图片

代码实现

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* middleNode(ListNode* head) {
        if(head==NULL || head->next == NULL)
            return head;
        
        ListNode* fast_ptr = head;
        ListNode* slow_ptr = head;
        
        while(fast_ptr != NULL && fast_ptr->next != NULL)
        {
            fast_ptr=fast_ptr->next->next;
            slow_ptr=slow_ptr->next;
        }
        
        return slow_ptr;
    }
};

你可能感兴趣的:(数据结构和算法)