先說下一個節點的結構:一個val域和一個next域
public class ListNode {
int val;
ListNode next = null;
public ListNode(int val) {
this.val = val;
}
}
一、已知鏈表的頭節點,將鏈表進行逆序。(不可以申請額外的空間)
public static ListNode reverseList(ListNode node) {
ListNode pre = null;
ListNode pNext = null;
while(node != null) {
pNext = node.next;
node.next = pre;
pre = node;
node = pNext;
}
return pre;
}
二、已知鏈表的頭節點,將鏈表從位置m到n逆序。注意:1<=m<=n<=鏈表長度(不允許申請額外空間)
思路:主要是要找到逆序的頭節點和尾巴,以及頭節點的前驅節點,和尾節點的後置節點
注意:如果m=1,說明是從第一個節點開始,那麼就需要修改頭節點
public static ListNode reverseListBetween(ListNode node,int m,int n) {
int index = 1;
ListNode p = node;
ListNode pre = null;
while(index <= n) {
if(index == m) {
ListNode temp = p;
ListNode tempPre = null;
ListNode tempNext = null;
for(int i = m;i <= n;i++) {//開始進行節點的逆序
tempNext = temp.next;
temp.next = tempPre;
tempPre = temp;
temp = tempNext;
}
if(pre == null) {//說明是從頭節點就開始翻轉
p.next = temp;
node = tempPre;//修改下頭節點
}else {
pre.next = tempPre;
p.next = temp;
}
index = n;
}
pre = p;
p = p.next;
index++;
}
return node;
}
三、求兩個鏈表公共的節點,若沒有則返回null
解題思路:給個圖就能知道!!!!從相同的位置開始判斷。交點之後都是相同的。
public static ListNode getIntersectionNode(ListNode node1,ListNode node2) {
//先求兩個鏈表的長度
int len1 = getLengthOfList(node1);
int len2 = getLengthOfList(node2);
//將指針移動到相同的位置
if(len1 > len2) {
for(int i = 0; i < len1 - len2;i++)
node1 = node1.next;
}else {
for(int i = 0; i < len2 - len1;i++)
node2 = node2.next;
}
//找相同的節點
while(node1 != null && node2 != null) {
if(node1 == node2)
return node1;
node1 = node1.next;
node2 = node2.next;
}
return null;
}
public static int getLengthOfList(ListNode node) {
int len = 0;
ListNode p = node;
while(p != null) {
len++;
p = p.next;
}
return len;
}
四、判斷一個鏈表中是否有環,若有則返回環的入口,若沒有則返回null
思路:設置快慢指針。
public static ListNode detectCycle(ListNode node) {
ListNode fast = node;
ListNode low = node;
while(low!=null && fast!=null && low.next != null && fast.next !=null) {
low = low.next;
fast = fast.next.next;
if(low == fast) {
//設置一個指針從頭節點開始
ListNode temp = node;
while(temp != low) {
temp = temp.next;
low = low.next;
}
return temp;
}
}
return null;
}
五、鏈表劃分:給定一個值x,將所有小於x的節點放在大於或等於x的節點前,且要保持這些節點原來的相對位置
解題思路:若是數組的話,實際上修改下排序的規則,並選擇一種穩定的排序即可,但是鏈表採用排序的方式就會稍微複雜。實際上可以設置兩個節點,遍歷鏈表,將小於x的節點連接到一個節點,將大於或等於x的節點連接到另外一個節點,最後再將兩個鏈表合併。
public static ListNode partition(ListNode node,int val) {
ListNode A = new ListNode(val);
ListNode B = new ListNode(val);
ListNode p1 = A;
ListNode p2 = B;
while(node != null) {
if(node.val < val) {
p1.next = node;
p1 = p1.next;
}else {
p2.next = node;
p2 = p2.next;
}
node = node.next;
}
p1.next = B.next;
p2.next = null;
return A.next;
}
六、複雜鏈表的複製。
結點結構有三部分:一個值域 一個next域,一個隨即域 ,指向任意節點。
public class RandomListNode {
int val;
RandomListNode next = null;
RandomListNode random = null;
public RandomListNode(int val) {
this.val = val;
}
}
public static RandomListNode copyRandomListNode(RandomListNode node) {
if(node == null)
return null;
//先複製節點
RandomListNode p = node;
while(p != null) {
RandomListNode temp = new RandomListNode(p.val);
temp.next = p.next;
p.next = temp;
p = p.next.next;
}
//複製節點的指向
p = node;
while(p != null) {
if(p.random != null) {
p.next.random = p.random.next;
}
p = p.next.next;
}
//拆分
p = node;
RandomListNode head = p.next;
RandomListNode t = head;
while(t.next != null) {
p.next = t.next;
t.next = t.next.next;
p = p.next;
t = t.next;
}
p.next = null;
return head;
}
未完待續。。。。