図1は、リスト削除する所定の値に等しい **ヴァル** すべてのノード。
アイデアの分析:
二つの補助ポインタPREVおよびCURを定義し、ときprev.next.data = valを削除することができます
主に最初のノードに対処することを忘れないでください
public void removeAllKey(int key) {
ListNode prev = this.head;
ListNode cur = this.head.next;
while(cur != null) {
if (prev.next.data == key) {
prev.next = cur.next;
cur = cur.next;
} else {
prev = cur;
cur = cur.next;
}
}
//处理第一个节点--最后处理
if (this.head.data == key) {
this.head = this.head.next;
}
}
前= CUR
public ListNode reverseList() {
if(this.head == null) {
return null;
}
ListNode cur = this.head;
ListNode prev = null;
ListNode newHead = null;
while (cur != null) {
ListNode curNext = cur.next;
if (curNext == null) {
newHead = cur;
}
cur.next = prev;
prev = cur;
cur = curNext;
}
return newHead;
}
public ListNode middleNode() {
// ListNode cur = this.head;
// int length = getlength()/2;
// for (int i = 0; i < length; i++) {
// cur = cur.next;
// }
// return cur;
ListNode fast = this.head;
ListNode slow = this.head;
while(fast != null && fast.next != null) {
fast = fast.next.next;
slow = slow.next;
}
return slow;
}
注:最初の有効なKか否かを決定する、最も効率的な方法は、ノードの数にステップを取ること-1、非常に速くポインタが歩行であると判断されている間、fast.next = NULLであり、k不当命令リターンヌルへ。
public ListNode FindKthToTail(int k) {
if (k <= 0 || this.head == null) {
return null;
}
ListNode fast = this.head;
ListNode slow = this.head;
for (int i = 0; i < k-1; i++) {
if (fast.next == null) {
return null;
}
fast = fast.next;
}
while(fast.next != null) {
fast = fast.next;
slow = slow.next;
}
return slow;
}
public static ListNode mergeTwoLists1(ListNode headA, ListNode headB){
ListNode newHead = new ListNode(-1);
ListNode tmp = newHead;
while (headA != null && headB != null) {
if (headA.data < headB.data) {
tmp.next = headA;
headA = headA.next;
tmp = tmp.next;
} else {
tmp.next = headB;
headB = headB.next;
tmp = tmp.next;
}
}
//如果a为空
if (headA == null) {
tmp.next = headB;
} else {
tmp.next = headA;
}
return newHead.next;
}
図6に示すように、所定の値Xへの書き込みコードがより小さい全て一覧表示されます参照するための2つの部分に分割されたXのノードは、行に以上であるX 前のノード。
分析思考:
①まず、2つの参照beginStartとbeginEnd、afterStartとafterEndが存在しなければならない
データリストノードk個の時間比は、beginStartノードにリンクされたリストのノードによって指されるときに、データがkよりも大きい場合②へafterStartノードを指します。
最初のリリースかどうかに注意を払うために時間を置きます。
③beginEndとafterStartをリンクします
終わりのように見えますが、実際には、二つの質問を逃した:
。Aリスト場合は、以下kより全てに、戻りは問題をBSません。。リスト内のすべての要素がkよりも大きい場合は、基地局の説明を直接返すことができるように、空である、プラス決意。
私たちは、BSの時間を返した場合、B。、あなたは、印刷されたリストの終了条件を見つけるnullであるが、リストが行われ、私たちはae.next最後のセットが空たいのでae.next必ずしも、空でないとき。だから、〜ちょっと実現可能
public ListNode partition(int x){
ListNode bs = null;
ListNode be = null;
ListNode as = null;
ListNode ae = null;
ListNode cur = this.head;
while (cur != null) {
if (cur.data < x) {
//判断是否为第一次加入
if (bs == null) {
bs = cur;
be = cur;
} else {
be.next = cur;
be = be.next;
}
} else {
//判断是否为第一次加入
if (as == null) {
as = cur;
ae = cur;
} else {
ae.next = cur;
ae = ae.next;
}
}
cur = cur.next;
}
//连在一起
if (be.next != null) {
be.next = as;
}
//判断是否k是否小于所以节点
if (bs == null) {
return as;
}
if (as != null) {
ae.next = null;
}
return bs;
}
7.重複ノードリストを削除し、リンクされたリストのノードは複製ソート、ノードが繰り返さを保持しない、ヘッド・ポインタ・リストを返します。
分析思考:
①重複ノードを見つけ、ノードcur.data =説明cur.next.dataは、重複データを有する場合、単一の補助変数CURトラバースリストを定義します。しかし、ノートでは、使用サイクルが決定されるように、複数のノードを繰り返しました。
②重複したノードを削除
注:
各裁判官cur.data == cur.next.data cur.nextがnullのとき、Aの裁判官が判断する必要があります。それ以外の場合は、NULLポインタ例外が発生します。
最後の中継ノードがtmp.next = nullに、次に、またノードである場合、B。
public ListNode deleteDuplication(){
ListNode cur = this.head;
ListNode newHead = new ListNode(-1);
ListNode tmp = newHead;
while (cur != null) {
//重复的节点
if(cur.next != null && cur.data == cur.next.data) {
//每一次都需要判断cur.next
while (cur.next != null && cur.data == cur.next.data) {
cur = cur.next;
}
cur = cur.next;
} else {
tmp.next = cur;
tmp = tmp.next;
cur = cur.next;
}
}
//最后一个节点如果也是重复的,需要将tmp.next置为空
tmp.next = null;
return newHead.next;
}
8.回文リスト。
どのように回文リストにそれを決定するには?
②リバースリスト
次に行き③fast/スローフォワード頭を
//单链表判断回文数
public boolean chkPalindrome() {
//为空
if (this.head == null) {
return false;
}
//一个数
if (head.next == null) {
return true;
}
//1、找到单链表的中间节点
ListNode fast = this.head;
ListNode slow = this.head;
while (fast != null && fast.next != null) {
fast = fast.next.next;
slow = slow.next;
}
//2、反转单链表
ListNode cur = slow.next;
while (cur != null) {
ListNode curNext = cur.next;
cur.next = slow;
slow = cur;
cur = curNext;
}
//3、fast/slow往前 head往后走
while (this.head != slow) {
if (this.head.data != slow.data) {
return false;
}
//偶数个数
if (this.head.next == slow) {
return true;
}
this.head = this.head.next;
slow = slow.next;
}
return true;
}
二つのリストを入力し、その第1の共通のノードを見つける9。
思路分析:
①将pL指向长链表,pL指向短的链表
②让长链表先走差值步
③分别一步一步走,如果节点相同就为相交
注意:
注意计算完长度后pS、pL重新赋值,还有最后循环退出的条件
public static ListNode getIntersectionNode(ListNode headA, ListNode headB) {
if(headA == null || headB == null) {
return null;
}
ListNode pL = headA;//永远指向长的单链表
ListNode pS = headB;//永远指向短的单链表
int lenA = 0;
int lenB = 0;
//求的lenA lenB
while (pL != null) {
lenA++;
pL = pL.next;
}
while (pS != null) {
lenB++;
pS = pS.next;
}
//pl、ps为空了
pL = headA;
pS = headB;
//差值-》最长的单链表先走len步
int len = lenA-lenB;
if(len < 0) {
pL = headB;
pS = headA;
len = lenB-lenA;
}
//让pL先走len步
for (int i = 0; i < len; i++) {
pL = pL.next;
}
//开始一起走 (pL != pS ) {一人一步走}
while (pL != pS) {
pL = pL.next;
pS = pS.next;
}
// if (pL == null) {
// return null;
// }
// return pL;
return pL;
}
判断链表是否有环可以使用快慢指针法,快的每次走两步,慢的每次走一步。若快的和慢的相遇则有环。
//判断链表是否有环
public boolean hasCycle() {
ListNode fast = this.head;
ListNode slow = this.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 false;
}
return true;
}
//创造一个环
public void creteLoop() {
ListNode cur = this.head;
while (cur.next != null) {
cur = cur.next;
}
cur.next = this.head.next;
}
11. 给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null
当slow=fast时,将slow指向头节点。slow和fast同时往后走,当slow和fast相等时的节点就是链表开始入环的第一个节点。
public ListNode detectCycle() {
ListNode fast = this.head;
ListNode slow = this.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 = this.head;
while (slow != fast) {
slow = slow.next;
fast = fast.next;
}
return slow;
}
证明:画图
12、给定一个链表,每个节点包含一个额外增加的随机指针,该指针可以指向链表中的任何节点或空节点。
要求返回这个链表的深拷贝。
思路分析:
①老新进行进行交替链接
②修改random
③将老新节点打开
public Node copyRandomList(Node head) {
if(head == null) {
return null;
}
Node cur = head;
//1、老新进行进行交替链接
while(cur != null) {
Node node = new Node(cur.val, cur.next, null);
Node tmp = cur.next;
cur.next = node;
cur = tmp;
}
//2、修改random
cur = head;
while(cur != null) {
if(cur.random != null) {
cur.next.random = cur.random.next;
cur = cur.next.next;
} else {
cur = cur.next.next;
}
}
//3、将老新节点打开
cur = head;
Node newHead = cur.next;
while(cur.next != null) {
Node tmp = cur.next;
cur.next = tmp.next;
cur = tmp;
}
return newHead;
}
最近做了挺多单链表的题,感觉虽然有的题目思路并不是特别难,但是一不小心就会造成空指针异常,因此做单链表的题要考虑全面,包括单链表的头、尾以及单链表是否为空,next是否为空。。。。