問題の説明
リンクリストを提供します。k個のノードごとに反転します。反転したリンクリストに戻ってください。
kは正の整数であり、その値はリンクリストの長さ以下です。
ノードの総数がkの整数倍でない場合は、最後に残っているノードを元の順序のままにしてください。
上級:
この問題を解決するために一定の余分なスペースのみを使用するアルゴリズムを設計できますか?
ノード内の値を変更するだけでなく、実際にノードを交換する必要があります。
例1:
输入:head = [1,2,3,4,5], k = 2
输出:[2,1,4,3,5]
例2:
输入:head = [1,2,3,4,5], k = 3
输出:[3,2,1,4,5]
例3:
输入:head = [1,2,3,4,5], k = 1
输出:[1,2,3,4,5]
例4:
输入:head = [1], k = 1
输出:[1]
問題解決のアイデア
1.
リンクリストの長さを数えます2.リンクリストが反転する回数を計算しますreverse_times = len / k;
- フリップの数が0の場合は、元のリンクリストに戻るだけです。
3.複数の変数を定義します
- cur_timeは、現在のフリップ数を保存します(フリップ数を決定するために使用できます)
- nhead仮想ヘッドノード(データを含まないセンチネルヘッドノードは、一般的なリンクリストの質問で定義できます)
- knextは、次のフリップのリンクリストヘッドノードを保存します(後続のリンクリストデータの損失を防ぐため)
- cur_headが現在反転する必要がある部分リンクリストのヘッドノードは、実際にはヘッドノードの前のノードです(これは部分反転に便利です)。
- 現在cur_tailによってフリップされている部分リンクリストのテールノードは、フリップが完了した後にknextに接続するために使用され、データが失われないようにします。
4.リンクリストの反転を実行します
- 1.次のフリップでリンクリストのヘッドノードの隣にknextをポイントします
- 2.ヘッド補間法を使用して反転します(ローカルリンクリストの最初のノードを保存するにはcur_tailを使用する必要があることに注意してください。フリップが完了すると、ローカルリンクリストの最後の位置になり、接続します次のリンクリストでそれ)
- 3.テールノードをヘッドノードに再割り当てし、テールノードの次のポインターがknextを指すようにします。
- 4.フリップの数+
15.next.nextに戻ります。
class Solution {
public ListNode reverseKGroup(ListNode head, int k) {
int len=0; //统计链表的长度
ListNode plen=head;
while(plen!=null){
len++;
plen=plen.next;
}
int reverse_times=len/k; //计算链表的翻转次数
if(k<=1 || reverse_times==0){
return head;
}
ListNode knext=head; //保存下一次翻转时候的链表头结点
int cur_times=0; //保存当前翻转次数
ListNode nhead=new ListNode(-1); //虚拟头结点,不包含任何数据
ListNode cur_head=nhead;
cur_head.next=head;
ListNode cur_tail=null;
while(cur_times<reverse_times){
//将knext指向下一次翻转时候的链表头结点
for(int i=0;i<k;i++){
knext=knext.next;
}
//使用头插法进行反转
ListNode p=cur_head.next; //保存当前需要头插的结点
cur_tail=cur_head.next;
ListNode next=null; //保存反转时下一个结点的指针
for(int i=0;i<k;i++){
next=p.next;
p.next=cur_head.next;
cur_head.next=p;
p=next;
}
//将尾部结点重新赋值给头部结点,并且让尾部结点的next指针指向knext
cur_head=cur_tail;
cur_tail.next=knext;
// System.out.println("3 "+knext.val);
cur_times++;
}
return nhead.next;
}
}