61.リンクリストの詳細なアイデアのローテーションとダブルポインターの詳細な分析

61.リンクリストのローテーション

リンクリストが与えられたら、リンクリストを回転させ、リンクリストの各ノードを右に位置移動します 。ここで、  は非負の数です。

例1:

入力:1-> 2-> 3-> 4-> 5-> NULL、k = 2
出力:4-> 5-> 1-> 2-> 3-> NULL
説明:
右に回転1ステップ:5 -> 1-> 2-> 3-> 4-> NULL
右に回転2ステップ:4-> 5-> 1-> 2-> 3-> NULL
例2:

入力:0-> 1-> 2-> NULL、k = 4
出力:2-> 0-> 1-> NULL
説明:
右に回転1ステップ:2-> 0-> 1-> NULL
右に回転2ステップ: 1-> 2-> 0-> NULL
右に回転3ステップ:0-> 1-> 2-> NULL
右に回転4ステップ:2-> 0-> 1-> NULL

アイデア

         この種のダブルポインターリンクリストの問題では、いくつかの詳細を扱う場合、2つのポインター間のステップ数の違いという1つの問題しかありません。では、最初のポインターが最初に実行する必要があるステップはいくつですか?

        2つの考え方があります。1つは最初のポインタが最後の空でない子ノードで停止する必要があり、停止条件はwhile(first && first-> next)である、もう1つは最初のポインタがで停止する必要があるというものです。リンクリストの空の終了ノードであり、停止条件は「while(first)」です。実際、それは一歩多く、一歩少なくするという問題です。具体的な取り扱いは、各人の習慣や好みに関連しています。

       作成者はここに提案をしています。リンクリストの最後の空でない子ノードで最初のポインタを停止することをお勧めします。その理由は次のとおりです。

1:最初のポインタは、空のノードで停止する場合は特に意味はありませんが、チェーンの最後の空でないノードで停止します。とにかく、これはチェーンの最後の有効なノードであることがわかっています。 。この問題はこの情報を効果的に使用します。そうでない場合は、正しいリンクリストのエンドノードを見つけるためにもう一度トラバースする必要があります。

2:空のノードで停止した場合、最初のポインターを計算していくつかの手順を実行すると、実際のパラメーター(たとえば、質問のk)とは異なる場合があり、この値によって、次のことがわからなくなる場合があります。それはk + 1です。それでもk-1、つまりlen-kであり、混乱しがちです。空でない子ノードの末尾で停止する場合、分析は比較的明確であり、間違いを犯しやすいものではありません。

       これは推測から外れるものではなく、潜在意識の良い習慣であり、間違いを犯しにくい行動方法です。

解決策:ダブルポインター

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
    int cntListNodes(ListNode *head) {
        if (NULL == head)
            return 0;
        
        int len = 0;
        while (head) {
            ++len;
            head = head->next;
        }

        return len;
    }
public:
    ListNode* rotateRight(ListNode* head, int k) {
        if (NULL == head || NULL == head->next || k < 1)
            return head;
        
        int len = cntListNodes(head);                    //计算长度,求实际移动位置
        k %= len;
        if (k == 0)
            return head;
        
        ListNode *first = head, *second = head;          //双指针
        while (k--)
            first = first->next;
        while (first && first->next) {                   //first要停在链表最后一个非空节点上
            first = first->next;
            second = second->next;
        }

        first->next = head;                              //将链表收尾相连,避免使用临时变量        
        head = second->next;                             //head指向新头节点
        second->next = NULL;                             //尾节点置空,防止链表成环

        return head;
    }
};

 

おすすめ

転載: blog.csdn.net/sy_123a/article/details/109122022