LeetCodeリンクリストトピック19最後のn番目の番号を削除するjava再帰的ソリューション&&マルチポインターソリューション

質問の詳細

この質問は、リンクリストの下部からn番目の番号を削除することです。リンクリストの性質上、リンクリストの長さを知るためにトラバースする必要があります。
各ノードが下からどのノードであるかを知るために、ここではバックトラッキングを使用してカウントし、現在の数をカウントします。
さらに、n番目の数値を削除するロジックは、n + 1番目の数値を使用してn-1の数値を指すことです(逆数)。
しかし、特別な場合があります。番号n-1は存在する必要があり、空でもかまいませんが、番号n + 1は存在しない可能性があります。削除する番号がリンクリストの先頭にある場合、要素n + 1は空であり、次を使用できます。ノードは空を指しますが、空のノードを使用して別のノードを指すことは絶対にしないでください。
したがって、n番目の要素がヘッドノードであるかどうかを判断する必要があります。そうである場合は、ヘッドノードの次の要素に戻ります。
コードの効果は100%と99.19%です

再帰的ソリューション

これは私が1か月前に遡及的思考を使用して、n-1とn +1の間のポイントを見つけるために行ったことです。
その中には特別な場合があります。

class Solution {
    
    
    private boolean flag = false;// 用以强制退出递归
    ListNode nSubOne = null,nPlusOne = null,nn=null;
    public ListNode removeNthFromEnd(ListNode head, int n) {
    
    
        backtrack(head,n);
        //只需要考虑一个特殊情况:删除的是头元素,则无法用n+1->n-1来删除n,那么直接返回head的next即可
        if(nn==head)
            return head.next;
        nPlusOne.next = nSubOne;
        return head;
    }
    public int backtrack(ListNode p, int n){
    
    
        if(flag)
            return 0;
        //判断是否为空
        if(p==null)
            return 0;
        int count = backtrack(p.next,n);
        count++;
        //进行判断,找到倒数n-1,n和n+1个数
        if(count==n-1)
            nSubOne = p;
        else if(count==n+1){
    
    
            nPlusOne = p;
            flag = true;
        }
        else if(count==n)
           nn = p;
        return count;
    }
}

マルチポインタソリューション

1か月以上後にこの質問をし、遡及的にすべてを忘れた場合、最初の反応はより多くのポインタです。
合計で3つのポインターがあり、1つはpreN、1つはnextN、1つはtailです。
テールはpreNを次の合計n回(つまり、間隔はn-1ポイント)リードし、nextNはpreNを次の2回(つまり1ポイント)リードします。
3つのポインターが同時に逆方向に実行され、tail.nextが空の場合、リンクリストの最後に到達したことを意味します。このとき、preNは下からn番目のポイントの直前にあり、nextNは下からn番目のポイントの後ろにあります。このとき、preN.net = nextNです。
これは上記と同じですが、特別な状況があります。n=リンクリストの長さの場合、つまり、テールが最初に実行された後、次は空になり、head.nextを直接返すことができます。
コードを見てください:

class Solution {
    
    
    public ListNode removeNthFromEnd(ListNode head, int n) {
    
    
        //没有什么记忆了,感觉还是得多刷题,不然这种做过的题都没什么记忆,用什么方法还得想半天,其实很不应该
        //需要考虑的是,这个是个链表,你只能一直访问下去
        //需要找到第倒数第n个节点,
        //只用一趟就解决
        //因为n有效,所以我直接把第一个节点往后走n个,领先n,然后两个一起往后走
        //这样的话,当领先的为null时,那么就能找到第n个了
        //这里因为是要删除,所以,还得搞一个近的
        //所以是n-1是n+1,总共三个指针
        if(n==0){
    
    
            return head;
        }
        ListNode ans=head, preN=head, nextN=head, tail=head;
        //当链表长度等于n时,需要考虑,其他都不存在问题
        
        for(int i=0; i<n; i++){
    
    
            tail = tail.next;
        }
        if(tail==null){
    
    //n=链表长度
            return head.next;
        }
        
        nextN = nextN.next.next;

        while(tail.next!=null){
    
    
            tail=tail.next;
            preN = preN.next;
            nextN = nextN.next;
        }
        preN.next = nextN;
        return head;
    }
}

時間計算量は同じで、どちらもO(n)であり、違いはありません。また、空間計算量もO(1)であり、上記の定数項よりもわずかに大きくなっています。
それはただ違う考えです。

おすすめ

転載: blog.csdn.net/qq_34687559/article/details/109182014