有了前面两个题目BM2 链表内指定区间反转,BM1 反转链表的铺垫,这一题就很简单了,思路如下:
链表的 k 个节点为一组,则有 len/k 组,即要逆置 len/k 次,于是就有了下列代码(当然,要借用前面两题的方法)。
- 前提铺垫
// 逆置链表
struct ListNode* ReverseList(struct ListNode* head ) {
if (head == NULL) return head;
struct ListNode* tmpHead = (struct ListNode*)malloc(sizeof(struct ListNode));
tmpHead -> next = NULL;
struct ListNode* pcur = head;
head = head->next;
while (head != NULL) {
pcur->next = tmpHead->next;
tmpHead->next = pcur;
pcur = head;
head = head->next;
}
pcur->next = tmpHead->next;
tmpHead->next = pcur;
return tmpHead->next;
}
// 求出链表长度
int listLength(struct ListNode* head) {
int len = 0;
while (head != NULL) {
len++;
head = head->next;
}
return len;
}
// 找到节点的前驱
struct ListNode* find_node_pre(struct ListNode* head, int m) {
struct ListNode* p = head;
int i = 1;
while (i < m - 1) {
p = p->next;
i++;
}
return p;
}
// 找到节点的后继
struct ListNode* find_node_next(struct ListNode* head, int m, int n) {
// 这里折磨我很久很久... m要分情况讨论,否则当 m==1 时node_n_next指向的是第n个元素的下一个元素,
// 就会导致下面的“从头到中”这一情况出错
struct ListNode* q;// q指向第 m 个元素
if(m == 1)
{
q = find_node_pre(head, m);
}
else
{
q= find_node_pre(head, m)->next;
}
int i = m;
while (i < n + 1 && q != NULL)// 要保证q不能为空
{
q = q->next;
i++;
}
return q;
}
// 找到某一链表的最后节点
struct ListNode* lastNode(struct ListNode* head)
{
struct ListNode* plast = head;
while (plast->next != NULL) {
plast = plast->next;
}
return plast;
}
// 逆置[m,n]范围链表
struct ListNode* reverseBetween(struct ListNode* head, int m, int n ) {
struct ListNode* tmp_ptr = (struct ListNode*)malloc(sizeof(struct ListNode)); // 临时节点
struct ListNode* node_m_pre = find_node_pre(head, m); // m的前一个节点
struct ListNode* node_n_next = find_node_next(head, m,n); // n的后一个节点
struct ListNode* node_m = find_node_pre(head, m + 1); // 第m个节点
struct ListNode* node_n = find_node_pre(head, n + 1); // 第n个节点
if (m == 1) {
if (n == 1) // 从点到点
return head;
else if (node_n_next != NULL) { // 从头到中
node_n->next = NULL;
head = ReverseList(head);
lastNode(head)->next = node_n_next;
return head;
} else // 从头到尾
return ReverseList(head);
} else { // m != 1
if (m == n) // 从点到点
return head;
else if (node_n_next != NULL) { // 从中到中
node_n->next = NULL; // 这两句话把[m,n]的链表断开
tmp_ptr = ReverseList(node_m); // 翻转中间的链表
// 接上前后的链表
lastNode(tmp_ptr)->next = node_n_next;
node_m_pre->next = tmp_ptr;
return head;
} else // 从中到尾
node_m_pre->next = ReverseList(
node_m);// 前面接上后面翻转过后的链表
return head;
}
}
- 本题核心代码
struct ListNode* reverseKGroup(struct ListNode* head, int k ) {
if(!head || k == 1) return head; // 空链表或者k=1时返回原始链表
int len = listLength(head); // 链表长度
for(int i = 0; i < len/k; i++) // 有 len/k 个长度为 k 的链表
{
head = reverseBetween(head, i*k+1, i*k+k);
}
return head;
}
上述代码结合在一起,即为本人所思考出的本题答案