前言
学会了链表,就需要在算法题上面进行实践
1.删除结点
思路:创建一个新的链表,遍历原链表,将不等于val的结点输入到新链表中。
注意:在输入第一个结点的时候需要判断是否为空。
为避免进入死循环,需要将新链表的尾结点的next指针置为NULL。
代码如下:
2.反转链表
思路1:新建一个链表,遍历旧链表,依次头插到新链表中。
思路2:运用三个指针思路,实现反转。(不需要创建新链表)这个思路不好想,可以记忆。
这里实现第二个思路,第一个思路读者可以下去自己实现。
原理:
设置三个指针,分别指向NULL,head,head->next。将n2->next指向n1,随后各往后走一步,即n1 = n2,n2= n3,n3 = n3->next,再循环n1 = n2,n2= n3,n3 = n3->next。但需要判断n3是否为空,如果为空便不往后走了,当n2为空的时候,n1便是反转链表的头指针。
代码如下:
3.寻找中间结点
思路:这是典型的快慢指针问题。通过设置两个指针,slow和fast。slow指针每次走一步,fast指针每次走两步。当fast指针走到结尾或者变为空时,此时的slow指针便是中间结点。
4.返回倒数第K个结点
思路1:运用快慢指针实现。让fast指针先走k步,然后slow和fast一起走,当fast走到结尾时,slow指针便是结果
思路2:将指针逆置,再从头结点开始算K。
这里实现第二个思路:
5.合并有序链表
思路:创建一个空链表,从头遍历两个旧链表,每次判断,小的结点放到新的链表中,然后该链表继续后移。依次重复直到有一个链表为空。最后将不为空的链表放到新链表的后面。
由于代码过长不好截图,这里贴一下代码:
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {
ListNode * newhead , * newtail;
newhead = newtail = (ListNode * )malloc(sizeof(ListNode ));
if(list1 ==NULL)
{
return list2;
}
if(list2 == NULL)
{
return list1;
}
else{
while(list1&&list2)
{
if(list1->val>list2->val)
{
newtail->next = list2;
newtail = newtail->next;
list2 =list2->next;
}
else
{
newtail->next = list1;
newtail = newtail->next;
list1 =list1->next;
}
}
if(list1)
{
newtail->next = list1;
}
if(list2)
{
newtail->next = list2;
}
ListNode * pcur = newhead->next;
free(newhead);
newhead = NULL;
return pcur;
}
}
6.切割链表
思路:分别创建两个链表,将大于x的结点放到一个链表中,小于x的结点放到另一个结点中。最后将小链表的尾结点指向大链表的头结点。
代码如下:
7.判断是否为回文结构
思路1:新建一个数组,将每个值都存放在数组中,然后设置一个left = 0指针和right = size-1指针,分别从两端进行判断。(不满足空间复杂度,仅供参考)
思路2:找到中间结点,然后将中间结点以及后面的进行逆置,从后半段的头指针与前半段的头指针开始遍历比较。
代码如下:
ListNode * SLfindmid(ListNode * head)
{
if(head == NULL)
{
return NULL;
}
ListNode * slow,* fast;
slow = fast = head;
while(fast&&fast->next)
{
fast = fast->next->next;
slow = slow ->next;
}
return slow;
}
ListNode * reverse(ListNode * head)
{
if(head == NULL)
return NULL;
ListNode * n1,*n2,*n3;
n1 = NULL;
n2 = head;
n3 = head->next;
while(n2)
{
n2->next = n1;
n1 = n2;
n2 = n3;
if(n3)
n3 = n3->next;
}
return n1;
}
class PalindromeList {
public:
bool chkPalindrome(ListNode* A) {
// write code here
//找中间结点
ListNode * mid = SLfindmid(A);
//逆置后面的链表
ListNode * pcur = reverse(mid);
//进行判断
while(pcur&&mid)
{
if(pcur->val == A->val)
{
pcur= pcur->next;
A = A->next;
}
else
{
return false;
}
}
return true;
}
};
8.判断相交链表
思路:先分别计算两个链表的长度,求其差的绝对值,让长的链表先走绝对值步,再一起向后遍历。
代码如下:
9. 判断是否为环
思路:运用快慢指针。还是慢指针走一步,快指针走两步,如果两个指针能相遇,那一定是环形的,如果快指针走到NULL,那便不是环形。
代码如下:
10.判断是否为环2
思路:快慢指针找到相遇的结点。再让头指针从头开始遍历与此同时相遇结点往后走,头指针和结点相遇的结点就是就是入环点。
代码如下:
11. 进行链表的深拷贝
思路:
1.在原链表基础上复制链表
*2.连接random指针(copy->random) = pcur->random->next;)
3.断开连接
代码如下:
typedef struct Node Node;
Node * buynode(int val)//申请新节点
{
Node* newnode = (Node* )malloc(sizeof(Node));
newnode->val = val;
newnode->next = newnode->random = NULL;
return newnode;
}
void add(Node * head)//添加copy
{
Node * pcur = head;
while(pcur)
{
Node * newnode = buynode(pcur->val);
newnode->next = pcur->next;
pcur->next = newnode;
pcur = pcur->next->next;
}
}
struct Node* copyRandomList(struct Node* head) {
if(head ==NULL)
return NULL;
//1.产生连接,复制链表
add(head);
//2.连接random
Node * pcur = head;
while(pcur)
{
Node* copy = pcur->next;
if(pcur->random)
copy->random = pcur->random->next;
pcur = copy->next;
}
//3.断开链接
Node * newhead = head->next;
Node * newtail = head->next;
pcur = head;
while(pcur->next->next)
{
pcur = pcur->next->next;
newtail->next = pcur->next;
newtail = newtail->next;
}
return newhead;
}
12.作者的话
如果读者对代码或者思路不解的话,可以私信作者哦