最近学习了链表的相关知识,现在我们通过一些链表oj题对链表的一些相关知识进行巩固吧!
第一题:
这道题该怎么玩呢?题目要求说是删除指定的节点,返回一个新的节点。那么我们可以从头遍历一遍,用一个cur作为临时变量,如果cur走到指定数的节点,就跳过该节点继续遍历直到cur为空。如果走到的不是指定数的节点,那么我们就将它拷贝到一个新的空间(用带哨兵位的头节点作为开头拷贝更为便利),需要注意的是最后一个节点的next要置成NULL,具体代码实现如下:
第二题:
做反转链表这道题时有两种方法:1.将每个节点按顺序依次头插到新的空间去,返回新空间的起始地址。2.利用n1、n2、n3三个变量实行迭代。现在我来讲讲第二个方法的具体实现:
第三题:
这道题主要考察的是快慢指针,快指针走两步慢指针走一步,题目很简单,直接上代码!
struct ListNode* middleNode(struct ListNode* head){
struct ListNode* fast,*slow;
fast =slow=head;
while(fast && fast->next)
{
fast =fast->next->next;
slow = slow->next;
}
return slow;
}
第四题:
这道题的解题思路和第三题非常的相似,求倒数第k个节点的方法就是用两个快慢指针,快指针先走k步,然后两个指针一起走直到快指针走到空,慢指针停留下来的地方就是倒数第k个节点。一下是此方法的实现:
struct ListNode* FindKthToTail(struct ListNode* pListHead, int k ) {
// write code here
struct ListNode* fast ,*slow;
if(pListHead ==NULL)
{
return NULL;
}
fast = slow =pListHead;
while(k--)
{
if(fast ==NULL)
{
return NULL;
}
fast =fast->next;
}
while(fast)
{
fast =fast->next;
slow =slow ->next;
}
return slow;
}
第五题:
这道题可以用两个指针分别遍历了l1和l2,两个指针一起走一起比较,较小的节点尾插在一个新的地方,最后返回新地方的地址,实现方式如下:
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2){
struct ListNode* guard =(struct ListNode*)malloc(sizeof(struct ListNode));
struct ListNode* tail =guard;
struct ListNode* cur1,*cur2;
cur1 =list1;
cur2 =list2;
while(cur1 &&cur2)
{
if(cur1->val <cur2->val)
{
tail->next =cur1;
tail =tail->next;
cur1=cur1->next;
}
else
{
tail->next =cur2;
tail =tail->next;
cur2=cur2->next;
}
}
while(cur1)
{
tail->next =cur1;
tail =tail->next;
cur1=cur1->next;
}
while(cur2)
{
tail->next =cur2;
tail =tail->next;
cur2=cur2->next;
}
tail->next=NULL;
struct ListNode* tmp =guard->next;
free(guard);
return tmp;
}
第六题:
这道题的难度等级是较难,但是咱们不用怕,用对正确的方法就行。我们创建两个哨兵位的头节点,第一个哨兵位的头节点尾插小于x的节点,第二个哨兵位的头节点尾插大于等于x的节点,最后将这两个链表合并成一个链表,返回guard1->next。(guard2尾插到guard1的后面),代码如下:
class Partition {
public:
ListNode* partition(ListNode* pHead, int x) {
// write code here
ListNode*guard1 =(struct ListNode*)malloc(sizeof(struct ListNode));
ListNode*guard2 =(struct ListNode*)malloc(sizeof(struct ListNode));
ListNode*tail1,*tail2,*cur;
tail1 =guard1;
tail2 =guard2;
cur =pHead;
while(cur)
{
if(cur->val <x)
{
tail1->next =cur;
tail1 =tail1->next;
}
else
{
tail2->next =cur;
tail2 =tail2->next;
}
cur =cur->next;
}
tail1->next =guard2->next;
free(guard2);
ListNode*tmp =guard1->next;
free(guard1);
tail2->next =NULL;
return tmp;
}
};
第七题:
回文就是对称,解这道题的思路就是先用之前的方法找出中间节点,再将头部到中间的节点进行逆序。最后一个指针从头,一个指针从中间节点依次比较,两个指针一直到NULL都是相等的话就是回文结构,反之就不是,实现方式如下:
class PalindromeList {
public:
struct ListNode* middleNode(struct ListNode* head){
struct ListNode* fast,*slow;
fast =slow=head;
while(fast && fast->next)
{
fast =fast->next->next;
slow = slow->next;
}
return slow;
}
struct ListNode* reverseList(struct ListNode* head){
struct ListNode*n1 =NULL;
struct ListNode*n2 =head;
struct ListNode*n3 =NULL;
while(n2)
{
n3 = n2->next;
n2->next =n1;
//实现迭代
n1 =n2;
n2 =n3;
}
return n1;
}
bool chkPalindrome(ListNode* head) {
// write code here
ListNode* mid =middleNode(head);
ListNode* rmid =reverseList(mid);
while(head &&rmid)
{
if(head->val ==rmid->val)
{
head =head->next;
rmid =rmid->next;
}
else
{
return false;
}
}
return true;
}
};
第八题:
这道题的思路就是先用两个指针分别遍历A和B并将节点个数求出来,如果A和B最终的头节点地址相同,那必定存在共同的节点,否则就为空。求出节点个数后求它们相减的绝对值,长节点的头指针先往后走他们节点个数的差值,再A和B同时走,最终地址相等的便是共同节点的地址。代码的具体细节与实现如下:
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
struct ListNode *cur1,*cur2;
cur1 =headA;
cur2 =headB;
int count1 =0;
int count2 =0;
while(cur1)
{
++count1;
cur1 =cur1->next;
}
while(cur2)
{
++count2;
cur2 =cur2->next;
}
if(cur1 != cur2)
{
return NULL;
}
int n =abs(count1-count2);
struct ListNode* l_ong =headA;
struct ListNode* s_hort =headB;
if(count1 <count2)
{
l_ong =headB;
s_hort =headA;
}
while(n--)
{
l_ong =l_ong->next;
}
while(l_ong && s_hort)
{
if(l_ong == s_hort)
{
return l_ong;
}
l_ong =l_ong->next;
s_hort=s_hort->next;
}
return NULL;
}
第九题:
判断是否有环我们可以用快慢指针,快指针一次走两步,慢指针一次走一步。快指针先进入环中,慢指针后进,当快指针的地址和慢指针相同时就存在环。代码如下:
bool hasCycle(struct ListNode *head) {
struct ListNode *fast,*slow;
slow = fast = head;
while(fast && fast->next)
{
slow =slow->next;
fast =fast->next->next;
if(fast ==slow )
{
return true;
}
}
return false;
}
第十题:
怎样求出开始入环的第一个节点呢?在这里想为大家介绍啊一种方法:公式法
那么代码就可以轻而易举写出来啦。
struct ListNode *detectCycle(struct ListNode *head) {
struct ListNode *fast,*slow;
fast =slow=head;
while(fast &&fast->next)
{
fast = fast->next->next;
slow = slow->next;
if(fast ==slow)
{
slow =head;
if(fast ==slow)
{
return fast;
}
while(fast &&fast->next)
{
fast = fast->next;
slow = slow->next;
if(fast ==slow)
{
return fast;
}
}
}
}
return NULL;
}
到这里链表oj题的讲述就结束了,如有不对就多多指正!