質問の詳細
この質問は、リンクリストの下部から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)であり、上記の定数項よりもわずかに大きくなっています。
それはただ違う考えです。