链表 这里我记录了链表的各种操作的算法,在后面的习题中会涉及到这些算法的思路。
反转一个单链表。
示例:
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL
反序的算法之前记录过,可以就地反序,也可以使用栈反序,这里为了节省时间和空间,就用就地反序的方法。
AC代码如下:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* reverseList(struct ListNode* head) {
if(head==NULL)
return head;
struct ListNode *p=head,*temp=head->next,*q=temp;
p->next=NULL;
while(q)
{
q=q->next;
temp->next=p;
p=temp;
temp=q;
}
return p;
}
请编写一个函数,使其可以删除某个链表中给定的(非末尾)节点,你将只被给定要求被删除的节点。
现有一个链表 -- head = [4,5,1,9],它可以表示为:
4 -> 5 -> 1 -> 9
示例 1:
输入: head = [4,5,1,9], node = 5
输出: [4,1,9]
解释: 给定你链表中值为 5 的第二个节点,那么在调用了你的函数之后,该链表应变为 4 -> 1 -> 9.
示例 2:
输入: head = [4,5,1,9], node = 1
输出: [4,5,9]
解释: 给定你链表中值为 1 的第三个节点,那么在调用了你的函数之后,该链表应变为 4 -> 5 -> 9.
说明:
- 链表至少包含两个节点。
- 链表中所有节点的值都是唯一的。
- 给定的节点为非末尾节点并且一定是链表中的一个有效节点。
- 不要从你的函数中返回任何结果。
一般删除链表结点,是将要删除的结点的前一个结点指向要删除的结点的后一个结店。本题中只给了要删除的结点,没有给头结点,而且是单链表,无法向前回溯,我们就不能用传统的方法了。仔细回想删除数组中一个数的过程,就是将这个数之后的所有数都向前移动一位,再将最后那个数删除掉。这种方法也可以应用在这里,不过由于链表的特性,我们不用把后面每个数的向前移,只需移动后一个结点,然后删除后一个结点即可。AC代码如下:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
void deleteNode(struct ListNode* node) {
node->val = node->next->val;
node->next = node->next->next;
}
给定一个单链表,把所有的奇数节点和偶数节点分别排在一起。请注意,这里的奇数节点和偶数节点指的是节点编号的奇偶性,而不是节点的值的奇偶性。
请尝试使用原地算法完成。你的算法的空间复杂度应为 O(1),时间复杂度应为 O(nodes),nodes 为节点总数。
示例 1:
输入: 1->2->3->4->5->NULL
输出: 1->3->5->2->4->NULL
示例 2:
输入: 2->1->3->5->6->4->7->NULL
输出: 2->3->6->7->1->5->4->NULL
说明:
- 应当保持奇数节点和偶数节点的相对顺序。
- 链表的第一个节点视为奇数节点,第二个节点视为偶数节点,以此类推。
将奇数结点和偶数结点排在一起,即每个结点都指向自己后面的第两个节点,最后尾结点连接第二个节点。需要注意的是,本题中给的链表的结点数可能是奇数,链表的尾部会有一个落单的结点无法交换位置。如果链表有0个、1个、2个结点的话,直接返回即可。AC代码如下:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* oddEvenList(struct ListNode* head) {
if(head==NULL || head->next==NULL || head->next->next==NULL)
return head;
struct ListNode *p1=head,*p2=head->next,*q=p2;
while(p2 && p2->next)
{
p1->next=p2->next;
p2->next=p2->next->next;
p1=p1->next;
p2=p2->next;
}
p1->next=q;
return head;
}
给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。
示例:
给定1->2->3->4
, 你应该返回2->1->4->3
.
说明:
- 你的算法只能使用常数的额外空间。
- 你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
本题不是交换相邻结点的值,则要进行指针的移动。交换相邻结点需要移动三个指针,例如->3->4->5,要移动3和4,则要将三个指针全断开,重新连接。我们可以定义两个指针p1和p2来进行移动操作,p1指向要移动的一队结点的第一个结点,p2指向p1的前一个结点。前两个节点比较特殊,只需要移动两个指针,做特殊处理。AC代码如下:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* swapPairs(struct ListNode* head) {
if(head==NULL || head->next==NULL)
return head;
struct ListNode *p=head->next->next;
head->next->next=head;
head=head->next;
head->next->next=p;
if(p==NULL || p->next==NULL)
return head;
struct ListNode *p1=head->next,*p2=p1->next;
while(p2->next)
{
p1->next=p2->next;
p2->next=p2->next->next;
p1->next->next=p2;
if(!p2->next) break;
p1=p2;
p2=p2->next;
}
return head;
}