LeetCode初级算法题——链表类——算法总结

LeetCode初级算法——链表类——算法总结

PS:算法并非原创,总结的本意在于温故知新、巩固知识。侵删。

1、删除链表中的节点
使用JAVA解答,代码如下:

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public void deleteNode(ListNode node) {
        node.val = node.next.val;
        node.next = node.next.next;
    }
}

算法解析:
从要删除的结点改为邻近的下一个结点,然后删去下一个节点。思想比较简单。

算法占用时空间资源:
LeetCode初级算法题——链表类——算法总结_第1张图片
时间

2、删除链表的倒数第N个节点
使用C++解答,代码如下:

/**
 * 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* first = (struct ListNode*)malloc(sizeof(ListNode));
        ListNode* second = (struct ListNode*)malloc(sizeof(ListNode));
        ListNode* dummy = (struct ListNode*)malloc(sizeof(ListNode));
        dummy->next = head;
        first = dummy;
        second = dummy;

        for(int i = 1; i <= n + 1; ++i) {
            first = first->next;
        }

        while(first != nullptr) {
            first = first->next;
            second = second->next;
        }
        second->next = second->next->next;

        return dummy->next;
    }
};

算法解析:
设置一个新的头部指针,指向给定的头结点,未到删除节点之前,first指针不断后移,直到找到要删除的结点,对于要删除的结点,如果未到达尾结点,first和second一直后移,利用fisrt和second之间的位置差进行倒数第N个元素的删除。一开始的for循环是为了形成位置差。

算法占用时空间资源:
LeetCode初级算法题——链表类——算法总结_第2张图片
LeetCode初级算法题——链表类——算法总结_第3张图片

3、反转链表
使用C++解答,代码如下:

/**
 * 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 此时指向子链表的最后一个结点
            
            // 将之前的头结点放入子链尾
            head->next->next = head;
            head->next = NULL;
            
            return new_head;
        }
    }
};

算法解析:
使用迭代算法进行解题。每一次迭代都反转当前结点之后的链表部分。当只有两个结点的时候,head->next->next和head->next将会实现倒转,new_head 将为最后一个结点,实现反转。而当有三个结点的时候,将最后两个看作一个结点,实现迭代操作。最终,多个结点将会有后往前形成反转。

算法占用时空间资源:
LeetCode初级算法题——链表类——算法总结_第4张图片
LeetCode初级算法题——链表类——算法总结_第5张图片

4、合并两个有序链表
使用C++解答,代码如下:

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

算法解析:
类似于有序数组的合并,使用mergeTwoLists进行迭代操作。mergeTwoLists实现的操作是将两个有序链表进行合并,如果l1此时元素较小,那么需要合并的就是l1->next和l2的部分,反之亦然,由此进行不断地合并操作,得出最后结果。

算法占用时空间资源:
LeetCode初级算法题——链表类——算法总结_第6张图片
LeetCode初级算法题——链表类——算法总结_第7张图片

5、回文链表
使用C++解答,代码如下:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    bool isPalindrome(ListNode* head) 
    {
        int lenth, i;    
        ListNode *point1, *point2, *point3;
        point3 = point2 = head;
        point1 = NULL;
        lenth = 0;
        if(head == NULL || head->next == NULL)
            return true;
        while(point3 != NULL)//取得长度
        {
            point3 = point3->next;
            lenth++;
        }
        for(i = 0;i < (lenth / 2);i++)//遍历到中间,并逆置
        {
            point3 = point2->next;
            point2->next = point1;
            point1 = point2;
            point2 = point3;
        }
        if((lenth % 2) == 1)
            point3 = point3->next;
        while(point3 != NULL && point1 != NULL)//两个指针开始向两头移动,取值比较
        {
            if(point3->val != point1->val)
                return false;
            point3 = point3->next;
            point1 = point1->next;
        }
        return true;//比较中没有发现不同值,则为回文链表
    }
};

算法解析:
point1指向前半段的最后一个链表结点【比如5个之中的第2个,6个之中的第3个】,point3指向指向后半段的第一个链表结点【比如5个之中的第4个,6个之中的第4个】。获取长度的时候,point3指向链表末尾,之后找到中点,并将两个指针安放到相应位置。之后进行双向遍历,point1向头部遍历,point3向尾部遍历,如果元素全部相同,那么则是回文链表。至于point1如何向头部遍历,依靠的是point2的穿针引线【point2->next = point1;point1 = point2;】。

算法占用时空间资源:
LeetCode初级算法题——链表类——算法总结_第8张图片
LeetCode初级算法题——链表类——算法总结_第9张图片

6、环形链表
使用C++解答,代码如下:

/**
 * 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)
        {
            return false;
        }
        ListNode* fast = head;
        ListNode* slow = head;
        do
        {
            if(!fast || !fast->next)
                return false;
            slow = slow->next;
            fast = fast->next->next;
        }
while(slow != fast);
        		return true;
    }
};

算法解析:
使用快慢指针,快指针每次移动两次,慢指针每次移动一次,如果快慢指针最终相遇,表示有环,返回true;如果直到fast指针移动到链表尾部,两者都没有相遇,那么没有环,返回flase.

算法占用时空间资源:
LeetCode初级算法题——链表类——算法总结_第10张图片
LeetCode初级算法题——链表类——算法总结_第11张图片

你可能感兴趣的:(Leetcode,算法,链表,leetcode)