私の連絡先情報
郵便メール:
2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
💎 欢迎各位大佬互三:私のホームページ
考察: 追加のスペースを空けず、元のリンク リストのみを変更する場合、どのような方法を使用する必要がありますか?
2 番目の要素から開始して、順番にヘッド挿入を実行するだけです。
次に、参照を変更し、最後の要素を null にポイントするだけです。
- class Solution {
- public ListNode reverseList(ListNode head) {
- //head为null,直接返回
- if(head == null){
- return head;
- }
-
- ListNode cur = head.next;
- //head变为了末尾元素,指向null
- head.next = null;
- while(cur!=null){
- //curn为cur的next节点,便于往后移动
- ListNode curn = cur.next;
- cur.next = head;
- head = cur;
- //更新cur
- cur = curn;
- }
- return head;
- }
- }
この質問に対して最初に思い浮かぶ方法は、間違いなく cnt を定義し、リンクされたリストを 1 回走査し、次に中央の数値を見つけて、戻り値を走査することです。この方法は非常に簡単ですが、中間ノードを見つけるためにリンクリストを一度だけ使用しますか?
これは新しいアイデアです。高速ポインタと低速ポインタを使用して、先頭から開始します。高速ポインタは毎回 2 つのノードを移動し、低速ポインタは毎回 1 つのノードを移動します。これで最終的な目標は達成されますか?
それでは、それを実装してみましょう:
- class Solution {
- public ListNode middleNode(ListNode head) {
- if(head == null){
- return null;
- }
- ListNode fast = head;
- ListNode slow = head;
- while(fast!= null&&fast.next!= null){
- fast = fast.next.next;
- slow = slow.next;
- }
- return slow;
- }
- }
これはより効率的でしょうか?
インタビューの質問 02.02. 最後から k 番目のノードを返します。
この質問で最初に思い浮かぶのは、一度走査して全長を取得し、最後から k 番目のノードを見つけることです。ただし、前の質問に基づいて、別の方法を考えることができます。同様に、fast ポインタと low ポインタを使用して、最初に fast go k-1 ノードを実行し、その後、slow と fast go を同時に実行します。fast の次が null の場合、fast が最後のノードに到達し、この時点で low が実行されることを意味します。は下から k 番目のノードです。
この質問は、入力 k が正当であることを示しているため、追加の判断は必要ありません。k が不正であるかどうかを判断する方法は、リンクされたリストの長さを直接求めることができないため、slow が歩きながら判断する必要があります。
- class Solution {
- public int kthToLast(ListNode head, int k) {
- if (head == null) {
- return -1;
- }
- ListNode fast = head;
- ListNode slow = head;
- int cnt = 0;
- while (cnt != k - 1) {
- //判断k的合法性,虽然本题不用判断
- fast = fast.next;
- if(fast == null){
- return;
- }
- cnt++;
- }
- //slow和fast同时移动
-
- while (fast.next != null) {
- fast = fast.next;
- slow = slow.next;
- }
- return slow.val;
- }
- }
アイデア:新しいノード newH を定義し、headA と headB の値を比較するだけで、マージされたリンク リストのヘッド ノードを最終的に見つけることができます。また、tmp = newH を定義し、小さい方のノードを定義する必要もあります。 tmp.next がそれを指します。
- class Solution {
- public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
- ListNode head = new ListNode();
- ListNode tmp = head;
-
- while(list1!=null&&list2!=null){
- if(list1.val < list2.val){
- tmp.next = list1;
- list1 = list1.next;
- tmp = tmp.next;
- }else{
- tmp.next = list2;
- list2 = list2.next;
- tmp = tmp.next;
- }
- }
- //判断剩余的情况
- if(list1!=null){
- tmp.next = list1;
- }else if(list2!=null){
- tmp.next = list2;
- }
- return head.next;
- }
- }
これはニウケのインタビューの質問です。質問の意味は、x の左側が x より小さく、右側が x より大きいです。元の順序は変更できません。
アイデア: 元のリンク リストを横断する新しいノード cur を定義し (元のリンク リストが変更されないようにするため)、x より大きいものをすべてリンク リストに入れ、x より小さいものをすべてリンク リストに入れ、最後に 2 つを接続します。リンクされたリスト。
- public class Partition {
- public ListNode partition(ListNode pHead, int x) {
- ListNode bs = null;
- ListNode be = null;
- ListNode as = null;
- ListNode ae = null;
- ListNode cur = pHead;
- while (cur != null) {
- if (cur.val < x) {
- //处理刚开始为null的情况
- if (bs == null) {
- bs = be = cur;
- }else{
- be.next = cur;
- be = be.next;
- }
- }else{
- if(as == null){
- as = ae = cur;
- }else{
- ae.next = cur;
- ae = ae.next;
- }
- }
- cur = cur.next;
- }
- //都是比x大的情况
- if(bs == null){
- return as;
- }
- be.next = as;
- //最后都要置为null,不然可能会报错
- if(as!=null){
- ae.next = null;
- }
- return bs;
- }
- }
それらが x より大きい場合、つまり bs = null の場合、as が直接返され、as.next が最終的に null に設定される場合に注意してください。
これは Niuke からの質問です。時間計算量と空間計算量の要件があるため、追加の配列を開くことはできません。そうしないと空間計算量が克服されず、通常の走査の計算量は O(n) になります。
考え方は次のとおりです。まず、リンクされたリストの中央の遅いノードを見つけ、次に先頭のノードを逆方向に走査し、遅いノードも逆方向に走査します。値が異なるということは、テキスト構造が返されていないことを意味します。
リンクされたリストを逆にして中間ノードを見つけることは以前にも行われていました。
- public class PalindromeList {
- public boolean chkPalindrome(ListNode head) {
- if (head == null) {
- return true;
- }
- //找到中间节点
- ListNode fast = head;
- ListNode slow = head;
- while (fast != null && fast.next != null) {
- fast = fast.next.next;
- slow = slow.next;
- }
- //从slow开始到末尾反转
- ListNode cur = slow.next;
- while (cur != null) {
- ListNode curn = cur.next;
- cur.next = slow;
- slow = cur;
- cur = curn;
- }
- //判断回文
- while (head != slow) {
- if (head.val != slow.val) {
- return false;
- }
- //判断偶数节点
- if (head.next == slow) {
- return true;
- }
- head = head.next;
- slow = slow.next;
- }
- return true;
- }
- }
なお、奇数ノードのリンクリストと偶数ノードのリンクリストの判定にも違いがある。
偶数ノードを先頭に移動すると無限ループが発生するため、偶数ノードについては追加の判定が必要となります。
図に示すように、交差するリンク リストは「Y」と同様の変換です。
以下の質問の写真も非常に鮮明です。
アイデア: A が短いか B が短いかに関係なく、それらの間の違いは交差前の部分であるため、長いリンク リストを差分だけ移動するだけで、2 つのリンク リストのノードが同時に後方に移動します。同一のノードが次のノードと交差します。
- public class Solution {
- public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
- ListNode pl = headA;
- ListNode ps = headB;
- int cnta = 0,cntb = 0;
- //计算两个链表的长度
- while(pl!=null){
- pl = pl.next;
- cnta++;
- }
- while(ps!=null){
- ps = ps.next;
- cntb++;
- }
- //如果链表b长,就更新pl,ps
- int len = cnta - cntb;
- //上面求长度时pl,ps都为空了,所以这里再重新指向
- pl = headA;
- ps = headB;
- if(len < 0){
- pl = headB;
- ps = headA;
- len = cntb - cnta;
- }
- //移动差值
- while(len!=0){
- pl = pl.next;
- len--;
- }
- //找到相交节点
- while(pl!=ps){
- pl = pl.next;
- ps = ps.next;
- }
- //链表不相交的情况
- if(pl == null) return null;
- return pl;
- }
- }
最後に、素の状況を追加する必要があります。この質問は追加しなくても合格できますが、厳密さを期すために追加する必要があります。
リンクされたリストに循環があるかどうかを判断する方法:まだスピードポインタを使用して、2人が遊び場で走っているように、1人は速く走り、もう1人はゆっくりと走ります。このとき、速い人は遅い人を確実に超えることができます。 , しかし、環がいなかったら、どんなに追いかけても捕まえられない女神のように、出会うことはできなかったでしょう。
ただし、2 つのノードを持つリングで、定義された高速ポインターが一度に 3 ステップを実行し、低速ポインターが一度に 1 ステップを実行する場合、それらは決して一致しません。
したがって、定義されたポインタは、一方が 2 歩、もう一方が 1 歩であれば、必ず一致することを判断する必要があります。
- public class Solution {
- public boolean hasCycle(ListNode head) {
- ListNode fast = head;
- ListNode slow = head;
- while(fast!=null&&fast.next!=null){
- fast = fast.next.next;
- slow = slow.next;
- if(fast == slow) return true;
- }
- return false;
- }
- }
今度は、前の質問でリングであるかどうかを判断した後、リングへの進入点を見つける必要があります。次のような推論ができます。
- public class Solution {
- public ListNode detectCycle(ListNode head) {
- ListNode fast = head;
- ListNode slow = head;
- //判断环
- while(fast!=null&&fast.next!=null){
- fast = fast.next.next;
- slow = slow.next;
- if(fast == slow) break;
- }
- if(fast == null||fast.next == null) return null;
- slow = head;
- //寻找环
- while(slow!=fast){
- slow = slow.next;
- fast = fast.next;
- }
- return slow;
- }
- }
追加する必要があるのは次のとおりです。
リングが非常に小さい場合、最終的な単純化結果は上記のようになりますが、元のコードはまだ問題ありません。