通过前两篇博客我们了解了链表的实现,那么今天我们来看看链表的oj题是如何完成的。
1、移除链表元素
题目要求我们删掉与val相同的节点。
方法一:我们可以写一个循环,首先创建两个节点,一个头节点,一个尾节点,开始时为空指针,将不为val的值尾插到新的尾后,当值与val相等,我们先创建next将cur释放掉后直接将next赋给cur即可。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* removeElements(struct ListNode* head, int val)
{
if(head == NULL)
{
return NULL;
}
struct ListNode* newhead,*newtail;
newhead = newtail = NULL;
struct ListNode* cur = head;
while(cur)
{
if(cur->val != val)
{
if(newtail == NULL)
{
newhead = newtail = cur;
}
else
{
newtail->next = cur;
newtail = newtail->next;
}
cur = cur->next;
}
else
{
struct ListNode* next = cur->next;
free(cur);
cur = next;
}
}
if(newtail)
{
newtail->next =NULL;
}
return newhead;
}
方法二:我们可以遍历链表将val相等的位置直接释放即可。这种方法别的地方也叫做迭代法。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* removeElements(struct ListNode* head, int val)
{
while (NULL != head && head->val == val)
{
head = head->next;
}
if (NULL == head)
{
return head;
}
struct ListNode* cur = head;
struct ListNode* prev = head;
while(cur)
{
if(cur->val == val)
{
//找到前一个
while(prev->next->val != val)
{
prev = prev->next;
}
struct ListNode* next = cur->next;
prev->next = next;
free(cur);
cur = next;
}
else
{
cur = cur->next;
}
}
return head;
}
2、反转链表
这道题我们先创建一个结构体指针指向链表的头指针然后头插到新的链表头,最后返回新的链表头。
struct ListNode* reverseList(struct ListNode* head)
{
struct ListNode* newhead = NULL;
struct ListNode* tail = head;
while(tail)
{
struct ListNode* next = tail->next;
tail->next = newhead;
newhead = tail;
tail = next;
}
return newhead;
}
3、返回链表中间节点
这道题我们可以使用快慢指针的方法,定义两个结构体指针。快指针走两步,慢指针走一步。
对于条件的控制我们应该区分出链表节点个数的奇偶性,当链表节点个数为奇数时fast应不能为空指针,当个数为偶数时fast的next不能为空。
struct ListNode* middleNode(struct ListNode* head)
{
struct ListNode* fast = head;
struct ListNode* slow = head;
while(head&&head->next)
{
head = head->next->next;
slow = slow->next;
}
return slow;
}
4、返回链表倒数第k个节点
这道题依旧是快慢指针,但与上一道题不同。我们先让fast指针走k步,然后两个指针同时走。直到fast为空,返回slow。
struct ListNode* FindKthToTail(struct ListNode* pListHead, int k )
{
// write code here
if(pListHead == NULL)
{
return NULL;
}
struct ListNode* fast = pListHead;
struct ListNode* slow = pListHead;
while(k)
{
if(fast ==NULL)
return NULL;
fast = fast->next;
k--;
}
while(fast)
{
fast = fast->next;
slow = slow->next;
}
return slow;
}
5、链表分割
这道题我们可以利用带哨兵位的头节点来解,malloc两个头节点两个尾节点,一个用来存放大于等于x的节点,一个用来存放小于x的节点。最后将两个链表连起来,再释放掉哨兵位。返回头指针即可。
class Partition {
public:
ListNode* partition(ListNode* pHead, int x)
{
// write code here
struct ListNode* bighead,*bigtail,*littlehead,*littletail;
bighead = bigtail =(struct ListNode*) malloc(sizeof(struct ListNode));
littlehead = littletail =(struct ListNode*) malloc(sizeof(struct ListNode));
struct ListNode* cur = pHead;
while(cur)
{
if(cur->val<x)
{
littletail->next = cur;
littletail = cur;
}
else
{
bigtail->next = cur;
bigtail = cur;
}
cur = cur->next;
}
littletail->next = bighead->next;
bigtail->next = NULL;
pHead = littlehead->next;
free(littlehead);
free(bighead);
return pHead;
}
};
6、合并链表
此题我们可以将l2中的节点放入l1中,只需要一个一个比较、插入即可。
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2)
{
struct ListNode* head1 = NULL;
struct ListNode* tail1 = NULL;
if(list1 == NULL)
{
return list2;
}
if(list2 == NULL)
{
return list1;
}
while(list1&&list2)
{
if(list1->val<list2->val)
{
if(tail1 == NULL)
{
head1 = tail1 = list1;
}
else
{
tail1->next = list1;
tail1 = tail1->next;
}
list1 = list1->next;
}
else
{
if(tail1 == NULL)
{
head1 = tail1 = list2;
}
else
{
tail1->next = list2;
tail1 = tail1->next;
}
list2 = list2->next;
}
}
if(list1)
tail1->next = list1;
if(list2)
tail1->next = list2;
return head1;
}