还是链表章节的题目
21.Merge Two Sorted Lists
功能:将两个已排序的链表合并成一个
//方法1:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
if(l1 == NULL)
return l2;
if(l2 == NULL)
return l1;
ListNode* small = l1->val < l2->val ? l1 : l2;
ListNode* large = l1->val >= l2->val ? l1 : l2;
ListNode* temp;
while(small->next)
{
if(small->next->val <= large->val )
small = small->next;
else
{
temp = small->next;
small->next = large;
small = large;
large = temp;
}
}
small->next = large;
return l1->val < l2->val ? l1 : l2;
}
};
//方法2
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
if(!l1)
return l2;
if(!l2)
return l1;
ListNode* head;
ListNode* cur;
if(l1->val <= l2->val)
{
head = l1;
l1 = l1->next;
}
else
{
head = l2;
l2 = l2->next;
}
cur = head;
while(l1&&l2)
{
if(l1->val <= l2->val)
{
cur->next = l1;
l1 = l1->next;
}
else
{
cur->next = l2;
l2 = l2->next;
}
cur = cur->next;
}
if(!l1)
cur->next = l2;
else
cur->next = l1;
return head;
}
};
总结:这道题一开始不知道怎么做,看了答案才知道了思路,上面给出了两种方法,似乎方法二的思路更直观,和方法一比较起来,用的时间也比较少。
方法二思路:
1.先判断特殊情况,如l1为空,返回l2,相反如l2为空,返回l1.
2.在比较两个链表的第一个数据,比较的目的是为了构建新排序的表头,在创建一个cur指针用于指向当前的元素
3.while循环l1和l2,并比较他们的每一对应项,谁的小,cur->next便指向谁,其指针也指向下一位。
4.最后看while循环的条件l1和l2那个先为空,把cur->next连接到还没有为空的结点上去。
方法一的思路比较巧妙:
1.还是先判断特殊情况。
2.构建两个标记指针small和Large,分别对应指向l1和l2的头,small指向两个头指针中数据较小的
3.此时small指向的链表认为是小链表,以该链表进入while循环
4.在循环中,再比较small->next和large指针指向数据的大小,若前者小,small = small->next,前进一位。
若后者小,则将small->next指向large,large指向了之前的small->next;small = small->next,在原本large指向的链 表上进一位,这样不断切换。
5.若最后small->next指向的链表先空了,则把large指向的链表剩余部分补上去。
19. Remove Nth Node From End of List
<span style="font-size:18px;">//My code
//功能:删除倒数第n个结点
/**
* 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* rear = head;
ListNode* front = head;
ListNode* prev;
while(n > 0)
{
front = front->next;
n--;
}
if(front == NULL)
return head->next;
while(front)
{
prev = rear;
rear = rear->next;
front = front->next;
}
prev->next = rear->next;
free(rear);
return head;
}
};</span>
<span style="font-size:18px;">//others code
ListNode* removeNthFromEnd(ListNode* head, int n)
{
ListNode** t1 = &head, *t2 = head;
for(int i = 1; i < n; ++i)
{
t2 = t2->next;
}
while(t2->next != NULL)
{
t1 = &((*t1)->next);
t2 = t2->next;
}
*t1 = (*t1)->next;
return head;
}</span>
总结:这一题也是从网上查到算法思路再写出来的。算法思路如下:
1.利用前后指针,前指针先走n步
2.然后前后指针一起走,前指针到链表尾端时前指针到了要删除的结点。
这里需要注意的是判断前指针是否为空的情况,别人的代码思路和上面的是一样的,不过他的更简洁,也少了删除的是头指针的判断。
328. Odd Even Linked List
<span style="font-size:18px;">//My code
//功能:把单链表中顺序为奇数的结点连在一起,顺序为偶数的结点连在一起,奇数结点排在前,偶数节点排在后。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* oddEvenList(ListNode* head) {
if(!head || !head->next || !head->next->next)
return head;
ListNode* curodd = head->next->next;
ListNode* evenhead = head->next;
ListNode* evenNode = head->next;
ListNode* cureven = head->next;
head->next = curodd;
while(curodd->next && curodd->next->next)
{
cureven = curodd->next;
evenNode->next = cureven;
evenNode = cureven;
curodd->next = curodd->next->next;
curodd = curodd->next;
}
if(!curodd->next)
evenNode->next = NULL;
else if(!curodd->next->next)
evenNode->next = curodd->next;
curodd->next = evenhead;
return head;
}
};</span>
//others code
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* oddEvenList(ListNode* head) {
if(!head || !head->next)
return head;
int count = 1;
ListNode *oddHead = head,*oddTail = head;
ListNode *evenHead = head->next,*evenTail = head->next;
ListNode *temp = evenHead->next;
oddHead->next = NULL;
evenHead->next = NULL;
while(temp != NULL)
{
if(count%2 == 1)
{
oddTail->next = temp;
oddTail = temp;
temp = temp->next;
oddTail->next = NULL;
}
else
{
evenTail->next = temp;
evenTail = temp;
temp = temp->next;
evenTail->next = NULL;
}
count++;
}
oddTail->next = evenHead;
return oddHead;
}
};
总结:这道题算是自己做出来了,其实思路也是比较简单,把顺序为奇数的结点和偶数的结点分别连起来,最后把偶数的结点的头结点连在奇数结点的尾节点上。这里在写的过程中遇到的一个小错误就是一开始没重复考虑到在原链表上处理,如果不是在一个循环里处理的话,那么像处理了奇链表,那么后面的偶结点就可能断了从而找不到。给出的别人的例子思路其实也是一样的,把他的也展示出来只是觉得他这样显得似乎更清晰一点。
148. Sort List
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* merge(ListNode* l1,ListNode* l2)
{
ListNode dummy(0);
ListNode* p = &dummy;
while(l1 && l2)
{
if(l1->val < l2->val)
{
p->next = l1;
p = p->next;
l1 = l1->next;
}
else
{
p->next = l2;
p = p->next;
l2 = l2->next;
}
}
if(!l1)
p->next = l2;
else if(!l2)
p->next = l1;
return dummy.next;
}
ListNode* sortList(ListNode* head) {
if(!head || !head->next)
return head;
ListNode* slow = head;
ListNode* fast = head->next;
while(fast && fast->next)
{
slow = slow->next;
fast = fast->next->next;
}
fast = slow->next;
slow->next = NULL;
return merge(sortList(head),sortList(fast));
}
};
总结:要求时间复杂度为o(nlog(n)),排序算法中归并排序符合这一要求,不过使用迭代的方法写出的归并排序需要更多的空间。算法思路:
1.使用快慢指针迅速找到链表的中点位置。
2.在链表的中点将链表分为两个链表,将两个链表一直细分析去, 直到不能再分位置
3.对所分的部分使用归并。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* insertionSortList(ListNode* head) {
ListNode* new_head = new ListNode(0);
ListNode* cur = head;
ListNode* prev = new_head;
prev->next = head;
while(cur)
{
if(cur->next && cur->next->val < cur->val)
{
while(prev->next && prev->next->val < cur->next->val)
prev = prev->next;
ListNode* temp = prev->next;
prev->next = cur->next;
cur->next = cur->next->next;
prev->next->next = temp;
prev = new_head;
}
else
cur = cur->next;
}
ListNode* res = new_head->next;
delete new_head;
return res;
}
};
总结:这道题就是要求写出单链表的直接插入排序算法,上面的算法思路还是比较清晰的。
1.构建cur、prev等节点,方便后面插入时使用。以cur为主节点,执行while循环,遍历链表,每循环一次cur先 后移动一位。
2.在while循环体中,判断cur当前结点和cur后面一个结点的数据值的大小,若cur比cur后面的一个结点的值小, 那么cur直接后移一位,不需要做其他操作。
3.如果cur的值比后面的一个值大,那么算法的结果应该是将cur的值插入到链表的开头到cur结点之间排好序的部 分的某一个位置。下面便执行这个操作。在这里再执行一遍while循环,从第一个结点开始,比较其值与cur结 点的大小,再决定把cur结点插入到哪个位置。
4.循环遍历完成后,整个链表就完成了排序。算法的时间复杂度为o(n^2)。注意插入过程中一系列的链表连接, 不要出错。