反转链表中的每 k 个节点块
Posted
技术标签:
【中文标题】反转链表中的每 k 个节点块【英文标题】:Reverse every k block of nodes in a link list 【发布时间】:2015-07-09 21:44:46 【问题描述】:我试图解决这个问题,即反转链接列表中的每 k 个节点块。我在每个外部 while 循环中处理 2*k 个元素。是否可以通过只处理每个外部 while 循环中的 k 个元素或不使用 hasknodes() 函数来完成?
样本输入:1->2->3->4->5 和 k = 3
样本输出:3->2->1->4->5
struct node *rev(struct node *head,int k)
if(k == 0 || k == 1)
return head;
int i;
struct node *prev,*temp,*curr,*newhead,*p,*thead;
p = head;
thead = head;
newhead = NULL;
while(p && hasknodes(p,k))
prev = NULL;
curr = p;
i = 0;
while(curr && i < k)
temp = curr->next;
curr->next = prev;
prev = curr;
curr= temp;
i++;
if(newhead == NULL)
newhead = prev;
else
thead->next = prev;
p->next = curr;
head = p;
if(p)
p = p->next;
if(newhead == NULL)
return head;
return newhead;
//The function hasknodes(p,k) checks if there are k elements present from the current position p.
【问题讨论】:
如果可以撤消最后一段的反转,则不必知道剩余长度。 样本输出不应该是2->1->4->3->5
吗?
其他限制?你能用一个向量作为临时的吗?
@AlexandruBarbarosie 那错了。查看编辑。
@DOUGLASO.MOEN 我们不能使用向量
【参考方案1】:
其实你不需要调用函数hasknodes;而是开始拾取节点并以相反的顺序链接它们(就像您在内部 while 循环中所做的那样),如果您过早到达列表的末尾,则重新附加反向列表的元素。然而,这种方法的缺点是代码变得有点复杂。
正如第一个评论者所写:O(2*n) 实际上与 O(n) 相同,因为 O(n) 意味着您的问题可以在时间 与 n 成比例 的时间内解决。所以,你基本上已经完成了:-)
【讨论】:
我看到你提到了第一条评论,但没有提到你在回答中基本上重复的第二条评论 我猜重新添加会消耗额外的内存。 @shivam mitra:不,重新附加不会消耗额外的内存。这只是调整节点链接的问题。【参考方案2】:将反转视为从一个列表弹出并推入另一个列表会很有帮助。您还需要知道 k 的前一个块的尾部,以便附加下一个。所以在伪代码中:
// let list be the head of the input list
prev_tail = sentinel; // fake previous tail node to append the first block
while list is not NULL
tail = list
block = NULL
for k times and while list isn't NULL
push(block, pop(list))
prev_tail->next = block
prev_tail = tail;
return sentinel->next;
现在在 C 中,push 和 pop 以通常的方式实现:
typedef struct node_s
struct node_s *next;
...
Node;
Node *reverse_blocks(Node *list, int k)
Node sentinel[1] = NULL;
Node *prev_tail = sentinel;
while (list)
Node *block = NULL;
Node *tail = list;
for (int i = 0; list && i < k; i++)
Node *pop = list;
list = list->next;
pop->next = block; // push(block, pop)
block = pop;
prev_tail->next = block;
prev_tail = tail;
return sentinel->next;
【讨论】:
【参考方案3】:您可以为此编写一个简单的递归解决方案:
struct node *reverse (struct node *head, int k)
struct node* current = head;
struct node* next = NULL;
struct node* prev = NULL;
int count = 0;
/*reverse first k nodes of the linked list */
while (current != NULL && count < k)
next = current->next;
current->next = prev;
prev = current;
current = next;
count++;
/* next is now a pointer to (k+1)th node,Recursively call for the
list starting from current.And make rest of the list as next of first node */
if(next != NULL)
head->next = reverse(next, k);
/* prev is new head of the input list */
return prev;
【讨论】:
以上是关于反转链表中的每 k 个节点块的主要内容,如果未能解决你的问题,请参考以下文章
JZ3.从尾到头打印链表;JZ14.链表中倒数第K个节点;JZ15.反转链表;JZ16.合并两个有序链表;JZ36.两个链表的第一个公共节点;JZ55.链表中环的入口节点;JZ56.删除链表中重复节点
JZ3.从尾到头打印链表;JZ14.链表中倒数第K个节点;JZ15.反转链表;JZ16.合并两个有序链表;JZ36.两个链表的第一个公共节点;JZ55.链表中环的入口节点;JZ56.删除链表中重复节点