この記事は、2021/08/12 に正式に開始された「LeetCode を征服する」シリーズ記事の 1 つです。LeetCode の一部の質問はロックされているため、このシリーズは、少なくともロックされていないすべての質問がクリアされるまで継続されます。LeetCode はまだ新しい質問を作成しているため、このシリーズの終了日は永遠になる可能性があります。この問題解決シリーズでは、さまざまな問題解決のアイデアとその最適化について説明するだけでなく、さまざまなプログラミング言語を使用して問題を解決する一般的な解決方法についてもまとめます。対応するアルゴリズム テンプレート。
PC 上でのコード ファイルの実行、デバッグ、共有を容易にするために、関連するウェアハウスも確立しました: https://github.com/memcpy0/LeetCode-Conquest。このウェアハウスでは、元の LeetCode 質問へのリンク、解決策コード、解決策記事へのリンク、類似質問の概要、一般的な解決策の概要などだけでなく、元の質問の頻度などの重要な情報も確認できます。および関連会社。他に好ましい解決策がある場合は、他の人と共有できます。
この一連の記事の内容はいつでも更新および変更される可能性があるため、リマインダーとして「LeetCode を征服する」シリーズの記事の目次をフォローして保存しておいてください。
head
ヘッド ノードと整数を持つ単一リンク リストが 与えられた場合 k
、リンク リストを k
連続部分に分割するアルゴリズムを設計してください。
各部分の長さはできる限り等しくなければなりません。どの 2 つの部分の長さの差も 1 を超えてはなりません。これにより、一部の部分が null になる可能性があります。
この k
パーツは、リンク リストに表示される順序で配置する必要があり、前のパーツの長さは後ろのパーツの長さ以上である必要があります。
k
上記の部分から構成される配列を返します 。
例 1:
输入:head = [1,2,3], k = 5
输出:[[1],[2],[3],[],[]]
解释:
第一个元素 output[0] 为 output[0].val = 1 ,output[0].next = null 。
最后一个元素 output[4] 为 null ,但它作为 ListNode 的字符串表示是 [] 。
例 2:
输入:head = [1,2,3,4,5,6,7,8,9,10], k = 3
输出:[[1,2,3,4],[5,6,7],[8,9,10]]
解释:
输入被分成了几个连续的部分,并且每部分的长度相差不超过 1 。前面部分的长度大于等于后面部分的长度。
ヒント:
- リンクリスト内のノード数は範囲内です
[0, 1000]
0 <= Node.val <= 1000
1 <= k <= 50
ソリューションの二重ループ
この質問では、指定されたリンクされたリストをkkに分割する必要があります。k 個の連続した部分。分割された各部分の長さは元のリンク リストの長さに関係するため、最初にリンク リストを走査してリンク リストnnん。
リンクリストnnの長さを取得するnの後には、quotient = ⌊ nk ⌋ \textit{quotient} = \Big\lfloor \dfrac{n}{k} \Big\rfloor を商=⌊kん⌋、k \texts{剰余} = n \bmod k に対する剰余 = n残り=nモッドkをkkに分割しますk個の部品のうち、最初に残った残り残りの部分の長さは、それぞれの商+ 1 商 + 1q u o t i e nt _+1、残りの各部分の長さは商 \textit{quotient}商。
リンクリストを分割する場合、リンクリストの先頭ノードから巡回を開始し、現在のノードをcurr currとして記録しますc u rr、各部分について、次の手順を実行します。
- カールするc u rr は現在のパートのヘッド ノードとして機能します。
- 現在のパーツの長さを計算します。part SizepartSizeパーツサイズ; _ _ _ _
- カールするパーツのサイズを後ろに移動します。パーツサイズステップ、次にcurr curr _c u rrは現在のパートの終了ノードです。
- くるくる_c u rr が現在のパートの終了ノードに到達すると、curr currc u rrと次のノードとの接続関係は、分割前にcurr curr。c u rr next nextの次のノード次へ; _ _
- 令currcurrあなたの次、次n e x tポインタはnull nullnull,完成 c u r r curr さあ、次へ次へ次の分割; _
- 将次次nextはcurr currに割り当てられますうーん。 _ _
上記の操作が完了すると、分離されたリンクリストの一部が得られます。kkが離れるまで上記の操作を繰り返すk個の部分、またはリンク リストの走査の終わり、つまりcurr currc u rr がnull nullを指しているヌル。 _ _
class Solution {
public:
vector<ListNode*> splitListToParts(ListNode* head, int k) {
int n = 0;
ListNode *temp = head;
while (temp) {
++n; temp = temp->next; }
int quotient = n / k, remainder = n % k;
vector<ListNode*> parts(k, nullptr);
ListNode* curr = head;
for (int i = 0; i < k && curr; ++i) {
parts[i] = curr;
int partSize = quotient + (i < remainder ? 1 : 0);
for (int j = 1; j < partSize; ++j) curr = curr->next;
ListNode *next = curr->next;
curr->next = nullptr;
curr = next;
}
return parts;
}
};
複雑さの分析:
- 時間計算量: O ( n ) O(n)O(n) ,其中 n n nはリンクされたリストの長さです。リンク リストと分離されたリンク リストの長さを取得するには、リンク リストを 2 回走査する必要があります。
- 空間複雑さ: O ( 1 ) O(1)お( 1 )。定数の余分なスペースのみが使用され、戻り値はスペースの複雑さには含まれないことに注意してください。