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;
}
}
算法解析:
从要删除的结点改为邻近的下一个结点,然后删去下一个节点。思想比较简单。
算法占用时空间资源:
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循环是为了形成位置差。
算法占用时空间资源:
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 将为最后一个结点,实现反转。而当有三个结点的时候,将最后两个看作一个结点,实现迭代操作。最终,多个结点将会有后往前形成反转。
算法占用时空间资源:
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的部分,反之亦然,由此进行不断地合并操作,得出最后结果。
算法占用时空间资源:
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;】。
算法占用时空间资源:
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.
算法占用时空间资源: