Leetcode reorder List

来源:互联网 发布:质量管理中的计量数据 编辑:程序博客网 时间:2024/05/06 16:36

Given a singly linked list LL0L1→…→Ln-1Ln,
reorder it to: L0LnL1Ln-1L2Ln-2→…

You must do this in-place without altering the nodes' values.

For example,

Given {1,2,3,4}, reorder it to {1,4,2,3}.

题目如下:

/** * Definition for singly-linked list. * struct ListNode { *     int val; *     ListNode *next; *     ListNode(int x) : val(x), next(NULL) {} * }; */


不同于一般的链表翻转,这里要求是链表要交叉着进行倒叙。  

我的思路是:先寻找链表的中间节点,然后在此处对后半段的链表进行翻转,这里就得到前后两段顺序正常的链表,然后进行合并。程序用到了3个最

基本的链表操作,寻找中间节点findMiddle(), 链表翻转reverseList(),以及最终的合并reorderList()。

(1)寻找中间节点findMiddle()

  给定一个链表*head, 利用一个first和second指针,前者每次前进一步,后者每次前进2步,当遍历完链表之后,first指针就是需要找的中间节点。但在leetcode上提交时几次出现了Runtime error 的问题。因为大多数寻找链表中间节点的操作只需要返回中间节点就够了,而在此处,除了找到中间节点first,还需要在此处将前后断开。在找到中间点first之后,要断开链表需要知道first的前驱,由于是单链表,无法直接得到前驱,所以我用了一个pre来保存。调用该函数后,first和second分别指向链表前一半和后一半的表头,代码如下:

struct Node* findMiddle(struct Node* head){  struct Node* first, *second ,*pre;  first = second = head;  if(NULL== head | NULL ==  head ->next)  return head;  else  {    while(second != NULL && second -> next != NULL ){  pre = first;  first =  first -> next;  second =  second -> next->next;}     second =  first; pre -> next =  NULL; first =  head;return second;    }}

(2)翻转链表操作 reverse().给定一个链表*head,对其翻转操作。这里我用的是原址翻转,也就是不增加额外空间,在原地对链表进行操作,需要的是改变原链表的指针指向,用到3个变量pre, cur, nex,代码如下:

//reverse the totall Linklist 'head' without extra spacestruct Node* reverse(struct Node* head){     struct Node* pre = NULL;struct Node* cur= head;struct Node* nex=  NULL;while(cur != NULL){  nex =  cur -> next;  cur -> next  = pre;  pre = cur;  cur = nex;}head -> next = NULL;head = pre;return pre;}

(3)在归并之前,首先调用寻找终点函数, mid = findMiddle(*head), 得到前后两段链表,然后对后半段链表调用上个函数mid = reverse(mid)得到后半段已经逆序后的mid链表。至此,已经有了两段链表head和mid,现在需要对他们进行挨个插入排序,即在head的第1,2,3,4,...个节点之后分别插入mid的第1,2,3,...个节点。

    这里有个细节需要注意,就是对于两段链表节点个数不一样的问题的边界处理。由于mid包含了原链表的中点,所以如果总节点个数为奇数个,那么必然是mid链表比head链表多出1个。每次进行处理的时候,需要先用head_nex和mid_nex来保存当前两段链表的后驱节点,然后插入过程需要进行判断,如果head_nex为空,则插入mid_nex,否则插入head_nex(这段逻辑大家好好体会下),代码如下:

void reorderList(ListNode *head)  {        if(head==NULL)             return;        else        {         struct ListNode* mid =  findMiddle(head);     mid = reverse(mid);                 // return the List reversed from the middle     struct ListNode* head_nex, *mid_nex;     head_nex = mid_nex = NULL;     struct ListNode* newlist = head;     if(head ==  mid)         ;     else         while(head !=NULL  && mid != NULL)       {      head_nex =  head -> next;      mid_nex =  mid-> next;                 //insert the second element into the first Linklist  mid -> next = (head -> next == NULL)?mid->next:head->next;      head -> next =  mid;     head =  head_nex;   mid =  mid_nex;      }          }        //     }


0 0
原创粉丝点击