LeetCode中幾道鏈表反轉相關題目(Reorder List、Rotate List、Reverse Nodes in k-Group)

三道很常見的面試題,Reorder List是一道完美洗牌題目,Rotate List是一道鏈表右轉題目,Reverse Nodes in k-Group是鏈表分組反轉題目,思路都比較清晰,考驗代碼基本功,涉及到指針的操作。

Reorder List

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}.

解題思路:首先找到鏈表的中間節點,然後將中間節點的右半部分反轉,接着將左右兩部分交替歸併到一起

struct ListNode {
    int val;
    ListNode *next;
    ListNode(int x) : val(x), next(NULL) {}
};

class Solution {
public:
    ListNode *findMid(ListNode *head) {//找出中間節點
        ListNode *fast = head->next;
        ListNode *slow = head;
        while(fast != NULL && fast->next != NULL){
            slow = slow->next;
            fast = fast->next->next;
        }
        return slow;
    }

    void merge(ListNode *&left,ListNode *&right){ //交替歸併
        ListNode *head = (ListNode *)malloc(sizeof(ListNode));
        ListNode *res = head;
        int cnt = 0;
        while (left != NULL && right != NULL) {
            if ((cnt & 1) == 0) {
                head->next = left;
                left = left->next;
            } else {
                head->next = right;
                right = right->next;
            }
            head = head->next;
            cnt ++;
        }
        if (left != NULL) {
            head->next = left;
        } else {
            head->next = right;
        }

        left = res->next;
    }
    ListNode* reverseList(ListNode *head){ //鏈表反轉
        if(head == NULL || head->next == NULL){
            return head;
        }
        ListNode *tail = head, *temp = NULL,*cur;
        while(tail->next != NULL){
            cur = tail->next;
            tail->next = temp;
            temp = tail;
            tail = cur;
        }
        tail->next = temp;
        return tail;
    }
    void createList(ListNode *&head){//創建鏈表
        int x;
        while(scanf("%d",&x) != EOF){
            if(x == 0) break;
            ListNode *node = (ListNode *)malloc(sizeof(ListNode));
            node->next = NULL;
            node->val = x;
            if(head == NULL) {
                head = node;
            } else {
                node->next = head;
                head = node;
            }
        }
    }

    void printList(ListNode *head){//打印
        while(head != NULL){
            cout<<head->val<<" ";
            head = head->next;
        }
        cout << endl;
    }
    void reorderList(ListNode *head) {
        if(head == NULL || head->next == NULL){
            return;
        }
        ListNode *mid;
        mid = findMid(head);
        ListNode *tail = reverseList(mid->next);
        mid->next = NULL; //將做半部分的尾指針設置爲NULL
        merge(head,tail);
    }
};

Rotate List

Given a list, rotate the list to the right by k places, where k is non-negative.

For example:
Given 1->2->3->4->5->NULL and k = 2,
return 4->5->1->2->3->NULL.

三道題中最簡單的一道,編程之美上有類似的字符串反轉題目。

解題思路:首先將整個鏈表反轉,然後分別找出左半部分和右半部分分別反轉即可。

struct ListNode {
    int val;
    ListNode *next;
    ListNode(int x) : val(x), next(NULL) {}
};


class Solution {
public:

    ListNode *reverseList(ListNode *head) {
        if(head == NULL || head->next == NULL) {
            return head;
        }
        ListNode *tail = head, *temp = NULL,*cur;
        while(tail->next != NULL) {
            cur = tail->next;
            tail->next = temp;
            temp = tail;
            tail = cur;
        }
        tail->next = temp;
        return tail;
    }

    int ListLength(ListNode *head) {
        if (head == NULL) {
            return 0;
        }
        int cnt = 0;
        while (head != NULL) {
            head = head->next;
            cnt ++;
        }
        return cnt;
    }

    ListNode *findKth(ListNode *head, int k) {
        if(k == 0) {
            return NULL;
        }
        ListNode *kthNode = head;
        while(k > 1) {
            kthNode = kthNode->next;
            k --;
        }
        return kthNode;
    }

    ListNode *rotateRight(ListNode *head, int k) {
        if(head == NULL || k == 0 || head->next == NULL) {
            return head;
        }

        int length = ListLength(head);
        k = k % length; //簡單處理

        head = reverseList(head);

        ListNode *kthNode = findKth(head,k); //找到左半部分和右半部分
        ListNode *right = NULL;
        if(kthNode != NULL) {
            right = reverseList(kthNode->next); //右半部分
            kthNode->next = NULL;
        }
        ListNode *left = reverseList(head); //左半部分

        ListNode *temp = left; //拼接到一起
        while (temp->next != NULL) {
            temp = temp->next;
        }
        temp->next = right;
        return left;
    }

    void createList(ListNode *&head){
        int x;
        while(scanf("%d",&x) != EOF){
            if(x == 0) break;
            ListNode *node = (ListNode *)malloc(sizeof(ListNode));
            node->next = NULL;
            node->val = x;
            if(head == NULL) {
                head = node;
            } else {
                node->next = head;
                head = node;
            }
        }
    }

    void printList(ListNode *head){
        while(head != NULL){
            cout<<head->val<<" ";
            head = head->next;
        }
        cout << endl;
    }
};

Reverse Nodes in k-Group

Given a linked list, reverse the nodes of a linked list k at a time and return its modified list.

If the number of nodes is not a multiple of k then left-out nodes in the end should remain as it is.

You may not alter the values in the nodes, only nodes itself may be changed.

Only constant memory is allowed.

For example,
Given this linked list: 1->2->3->4->5

For k = 2, you should return: 2->1->4->3->5

For k = 3, you should return: 3->2->1->4->5

貌似去年美團的一道面試題,字符串的分組反轉,思路最清晰,但是處理起來較爲複雜

struct ListNode {
    int val;
    ListNode *next;
    ListNode(int x) : val(x), next(NULL) {}
};

class Solution {
public:
    ListNode *reverseList(ListNode *head) { //反轉
        if (head == NULL || head->next == NULL) {
            return head;
        }

        ListNode *tail = head, *temp = NULL, *cur;

        while (tail->next != NULL) {
            cur = tail->next;
            tail->next = temp;
            temp = tail;
            tail = cur;
        }
        tail->next = temp;
        return tail;
    }

    int ListLength(ListNode *head) { //計算鏈表長度
        if (head == NULL) {
            return 0;
        }
        int cnt = 0;
        while (head != NULL) {
            head = head->next;
            cnt ++;
        }
        return cnt;
    }
    ListNode *ListAppend(ListNode *first, ListNode *second) {
        if (first == NULL) {
            first = second;
            return first;
        }
        ListNode *res = first;
        while (res->next != NULL) {
            res = res->next;
        }
        res->next = second;
        return first;
    }
    ListNode *reverseKGroup(ListNode *head, int k) {
        if (k == 1 || k == 0 || head == NULL || head->next == NULL) {
            return head;
        }
        int length = ListLength(head);
        if(k > length) {
            return head;
        }//簡單特例判斷
        ListNode *p = head;
        ListNode *res = NULL;
        while (p != NULL) {
            int cnt = 1;
            ListNode *temp = p;
            while (cnt < k && temp != NULL) { //找到K個節點一組
                cnt ++;
                temp = temp->next;
            }
            if (temp == NULL) { //如果不夠K,那麼就直接拼接
                res = ListAppend(res,p);
                break;
            }
            ListNode *pnext = temp->next; //保留後續節點
            temp->next = NULL; 
            ListNode *tail = reverseList(p);//反轉當前K個節點
            if (res == NULL) {
                res = tail;
            } else {
                res = ListAppend(res, tail); //拼接
            }
            p = pnext; //恢復
        }
        return res;
    }
    void createList(ListNode *&head){
        int x;
        while(scanf("%d",&x) != EOF){
            if(x == 0) break;
            ListNode *node = (ListNode *)malloc(sizeof(ListNode));
            node->next = NULL;
            node->val = x;
            if(head == NULL) {
                head = node;
            } else {
                node->next = head;
                head = node;
            }
        }
    }

    void printList(ListNode *head){
        while(head != NULL){
            cout<<head->val<<" ";
            head = head->next;
        }
        cout << endl;
    }
};



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章