删除链表中的节点
请编写一个函数,使其可以删除某个链表中给定的(非末尾)节点,你将只被给定要求被删除的节点。
现有一个链表 -- 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.
说明:
- 链表至少包含两个节点。
- 链表中所有节点的值都是唯一的。
- 给定的节点为非末尾节点并且一定是链表中的一个有效节点。
- 不要从你的函数中返回任何结果。
这道题只给了一个节点,没有前驱,如何删除该节点元素?
解题方法很巧妙:
把要删除的节点,用该节点后面的节点的内容覆盖,然后删掉后面的那个节点。
如ABCDEFG,删除D,我们先用E占D的位置,变成ABCEEFG,然后把后面的E删除。
代码如下
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
void deleteNode(ListNode* node) {
ListNode* p = node->next;
node->val=p->val;
node->next = p->next;
delete p;
}
};
删除链表的倒数第N个节点
给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。
示例:
给定一个链表: 1->2->3->4->5, 和 n = 2. 当删除了倒数第二个节点后,链表变为 1->2->3->5.
说明:
给定的 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* p1 = head;
ListNode* p2 = head;
ListNode* p ;
if(head->next == NULL && n==1){
delete head;
return NULL;
}
for(int i=0;i<n;i++){
p2=p2->next;
}
if(p2==NULL){
p=head;
head = head->next;
delete p;
return head;
}
while(p2->next!=NULL){
p1=p1->next;
p2=p2->next;
}
p=p1->next;
p1->next = p->next;
delete p;
return head;
}
};
反转链表
反转一个单链表。
示例:
输入: 1->2->3->4->5->NULL 输出: 5->4->3->2->1->NULL
进阶:
你可以迭代或递归地反转链表。你能否用两种方法解决这道题?
迭代法:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* reverseList(ListNode* head) {
if(head==NULL)return head;
ListNode* prev=NULL,* p=head,* temp = head->next;
while(temp!=NULL){
p->next = prev;
prev = p;
p=temp;
temp=temp->next;
}
p->next=prev;
return p;
}
};
合并两个有序链表
将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例:
输入:1->2->4, 1->3->4 输出:1->1->2->3->4->4
/**
* 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) {
ListNode*head,*p;
head = new ListNode(0);
p=head;
while(l1!=NULL&&l2!=NULL){
if(l1->val<l2->val){
p->next = l1;
p=l1;
l1=l1->next;
}
else{
p->next = l2;
p=l2;
l2 = l2->next;
}
}
if(l1!=NULL) p->next = l1;
if(l2!=NULL) p->next =l2;
return head->next;
}
};
回文链表
请判断一个链表是否为回文链表。
示例 1:
输入: 1->2 输出: false示例 2:
输入: 1->2->2->1 输出: true进阶:
你能否用 O(n) 时间复杂度和 O(1) 空间复杂度解决此题?
思路:反转后半部分链表再比较
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* reverseList(ListNode* head) {
if(head==NULL)return head;
ListNode* prev = NULL,*p = head,*tmp = head->next;
while(tmp!=NULL){
p->next =prev;
prev = p;
p=tmp;
tmp = tmp->next;
}
p->next =prev;
return p;
}
bool isPalindrome(ListNode* head) {
if(head==NULL)return true;
ListNode * l=head,* r=head;
ListNode * m = head;
while(r->next!=NULL){
r=r->next;
if(r->next!=NULL){
r=r->next;
m = m->next;
}
}
m= m->next;
m=reverseList(m);
while(m!=NULL){
if(m->val!=l->val)
return false;
m=m->next;
l=l->next;
}
return true;
}
};
环形链表
给定一个链表,判断链表中是否有环。
进阶:
你能否不使用额外空间解决此题?
思路:快慢指针即可,快指针每次走两步,慢指针每次走一步。快指针追上慢指针,则表示有环。
class Solution {
public:
bool hasCycle(ListNode *head) {
if(head==NULL||head->next==NULL)return false;
ListNode * fast = head, *slow = head;
while(fast!=NULL){
fast = fast->next;
if(fast){
slow = slow->next;
fast = fast->next;
}
if(fast == slow){
return true;
}
}
return false;
}
};