【题目】
给定链表的头节点head,实现删除链表的中间节点的函数。
例如:
链表为空或长度为1,不删除任何节点;
1 -> 2,删除节点1;
1 -> 2 -> 3,删除节点2;
1 -> 2 -> 3 -> 4,删除节点2;
1 -> 2 -> 3 -> 4 -> 5,删除节点3;
进阶:
给定链表的头节点head、整数a和b,实现删除位于a/b处节点的函数。
例如:
链表:1 -> 2 -> 3 -> 4 -> 5,假设a/b的值为r。
如果r等于0,不删除任何节点;
如果r在区间(0,1/5]上,删除节点1;
如果r在区间(1/5,2/5]上,删除节点2;
如果r在区间(2/5,3/5]上,删除节点3;
如果r在区间(3/5,4/5]上,删除节点4;
如果r在区间(4/5,1]上,删除节点5;
如果r大于1,不删除任何节点。
【解答1】
分析原问题,如果链表为空或者长度为1,,不需要调整,则直接返回;如果链表的长度为2,将头节点删除即可;当链表长度到达3,应该删除第2个节点;当链表的长度为4,应该删除第2个节点;当链表的长度为5,应该删除第3个节点……也就是链表长度每增加2(3,5,7……),要删除的节点就后移一个节点。
【代码实现1】
struct Node{
int value;
Node *next;
Node(int data){
value = data;
}
};
static Node *removeMidNode(Node *head){
if (head == nullptr || head->next == nullptr){
return head;
}
if (head->next->next == nullptr){
return head->next;
}
Node *pre = head;
Node *cur = head->next->next;
while (cur->next != nullptr && cur->next->next != nullptr){
pre = pre->next;
cur = cur->next->next;
}
pre->next = pre->next->next;
return head;
}
【解答2】
对于进阶问题,如何根据链表的长度n,以及a与b的值决定该删除的节点是哪一个节点。根据如下方法:先计算double r = ((double)(a*n)) / ((double)b)的值,然后r向上取整后的整数值代表该删除的节点是第几个节点。
【代码实现2】
static Node *removeByRatio(Node *head, int a, int b){
if (a < 1 || a > b){
return head;
}
int n = 0;
Node *cur = head;
while (cur != nullptr){
n++;
cur = cur->next;
}
n = ceil((double)(a * n) / b);
if (n == 1){
head = head->next;
}
if (n > 1){
cur = head;
while (--n != 1){
cur = cur->next;
}
cur->next = cur->next->next;
}
return head;
}
【来源】
《程序员代码面试指南(IT名企算法与数据结构题目最优解)》左程云