Write a function to delete a node (except the tail) in a singly linked list, given only access to that node.
Supposed the linked list is 1 -> 2 -> 3 -> 4
and you are given the third node with value 3
, the linked list should become 1 -> 2 -> 4
after calling your function.
刚开始看到这个题目时,我的第一反应是把待删除结点的后驱结点连在前驱结点的后面。再一细看,发现程序接口只告诉我们待删除结点,因为是单链表的结构,所以我们顺着链子找下去,只能找到后驱结点,无法找到前驱结点。我有点傻眼了。再读一遍题目,发现题目中有个小暗示“except the tail”,为什么不能是最后一个结点呢?难道删除那个结点是最后一个结点。很自然的,我们就能想到把这个链表删一个结点的问题转化成数组删除一个元素的问题。从一个数组中删除一个元素,我们通常的做法是把待删除元素位置后的元素都向前移动一个位置,最后再改变数组长度。解这个链表删一个结点的问题,也是类似的做法,把后一个结点的值赋给前一个结点,最后删除尾巴结点。
代码如下:
/**
* 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;
while(node->next) {
p = node;
node = node->next;
p->val = node->val;
}
p->next = NULL;
delete node;
}
};
上面提到的方法是模拟数组删除一个元素的算法去做的,所以时间复杂度为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:
void deleteNode(ListNode* node) {
ListNode* p;
p = node;
node = node->next;
p->val = node->val;
p->next = node->next;
delete node;
}
};