1. 輸入一個鏈表,從尾到頭打印鏈表每個節點的值。
先遞歸,再添加節點的值即可。
代碼如下:
ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
ArrayList<Integer> array = new ArrayList<Integer>();
if (listNode != null) {
array = printListFromTailToHead(listNode.next);
array.add(listNode.val);
}
return array;
}
2. 輸入一個鏈表,輸出該鏈表中倒數第k個結點。
設置兩個指針指向鏈表頭,一個先走K步,然後兩個指針一起向後移動,第一個指針到尾部時候,第二個指針即倒數第K個結點。
代碼如下:
ListNode FindKthToTail(ListNode head, int k) {
if (head == null | k < 0) return null;
ListNode pointer1 = head;
ListNode pointer2 = head;
int count = 1;
while (pointer2.next != null) {
if (count < k) {
pointer2 = pointer2.next;
count++;
} else {
pointer2 = pointer2.next;
pointer1 = pointer1.next;
}
}
if (count == k)
return pointer1;
else
return null;
}
3. 輸入一個鏈表,反轉鏈表後,輸出鏈表的所有元素。
用兩種方式來解決,第一種遞歸解決,考慮有一個k結點,將k結點後鏈表逆轉後的頭結點返回,此時k結點指向的結點是逆轉後鏈表的尾部結點,將k結點移到逆轉後鏈表的尾部即可。
代碼如下:
ListNode ReverseList(ListNode head) {
if (head == null) return null;
//遞歸解決
if (head.next == null)
return head;
ListNode head1 = ReverseList(head.next);
head.next.next = head;
head.next = null;
return head1;
}
第二種方式,通過在原始鏈表中操作,採用頭插法即可逆置。
代碼如下:
ListNode ReverseList(ListNode head) {
if (head == null) return null;
ListNode pointer = head.next;
ListNode pointer1 = head;
while (pointer != null) {
head.next = pointer.next;
pointer.next = pointer1;
pointer1 = pointer;
pointer = head.next;
}
return pointer1;
}
4. 輸入兩個單調遞增的鏈表,輸出兩個鏈表合成後的鏈表,當然我們需要合成後的鏈表滿足單調不減規則。
兩種方式解決,一種遞歸,首先比較兩個鏈表的頭結點,獲得了一個較小的結點,此時應該遞歸比較結點後的鏈表和另一個鏈表即可。
代碼如下:
ListNode Merge(ListNode list1, ListNode list2) {
if (list1 == null) return list2;
if (list2 == null) return list1;
ListNode pointer1 = list1;
ListNode pointer2 = list2;
//遞歸實現
if (list1.val <= list2.val) {
pointer1 = list1;
pointer1.next = Merge(list1.next, list2);
} else {
pointer1 = list2;
pointer1.next = Merge(list1, list2.next);
}
return pointer1;
}
第二種迭代解決。採用尾插法,不斷的將較小的結點插入。代碼如下:
ListNode Merge(ListNode list1, ListNode list2) {
if (list1 == null) return list2;
if (list2 == null) return list1;
ListNode pointer1 = list1;
ListNode pointer2 = list2;
ListNode head = new ListNode(0);
ListNode rear = head;//尾插法
while (pointer1 != null && pointer2 != null) {
if (pointer1.val <= pointer2.val) {
rear.next = pointer1;
rear = pointer1;
pointer1 = pointer1.next;
} else if (pointer1.val > pointer2.val) {
rear.next = pointer2;
rear = pointer2;
pointer2 = pointer2.next;
}
}
if (pointer1 != null)
rear.next = pointer1;
else if (pointer2 != null)
rear.next = pointer2;
return head.next;
}
5. 輸入一個複雜鏈表(每個節點中有節點值,以及兩個指針,一個指向下一個節點,另一個特殊指針指向任意一個節點),返回結果爲複製後複雜鏈表的head。
首先在原始複雜鏈表上進行復制結點操作,例如1->2->3變爲1->1->2->2->3->3。然後將特殊的指針也進行賦值。每個特殊指針不爲空的結點後一個結點的特殊指針指向,前一個結點特殊指針指向的結點的下一個。最後將結點分離出來即可。
代碼如下:
/*
public class RandomListNode {
int label;
RandomListNode next = null;
RandomListNode random = null;
RandomListNode(int label) {
this.label = label;
}
}
*/
RandomListNode Clone(RandomListNode pHead) {
if (pHead == null) return null;
RandomListNode pointer = pHead;
while (pointer != null) {
RandomListNode node = new RandomListNode(pointer.label);
node.next = pointer.next;
pointer.next = node;
pointer = node.next;
}
pointer = pHead;
while (pointer != null) {
if (pointer.random == null)
pointer.next.random = null;
else {
pointer.next.random = pointer.random.next;
}
pointer = pointer.next.next;
}
pointer = pHead;
RandomListNode result = pHead.next;
while (pointer != null) {
RandomListNode node = pointer.next;
pointer.next = pointer.next.next;
pointer = pointer.next;
if (pointer != null && pointer.next != null) {
node.next = pointer.next;
}
}
return result;
}
6. 輸入兩個鏈表,找出它們的第一個公共結點。
有多種方式,這裏介紹兩種,可以用兩個棧將兩個鏈表結點保存,然後兩個棧同時出棧進行對比即可,另一個先計算鏈表長度,然後進行比對。這裏只給出第二種的代碼,如下:
ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
int len1 = 0, len2 = 0;
if (pHead1 == null | pHead2 == null) return null;
ListNode pointer1 = pHead1, pointer2 = pHead2;
while (pointer1 != null) {
len1++;
pointer1 = pointer1.next;
}
while (pointer2 != null) {
len2++;
pointer2 = pointer2.next;
}
pointer1 = pHead1;
pointer2 = pHead2;
int more = Math.abs(len1 - len2);
if (len1 <= len2) {
pointer2 = pHead1;
pointer1 = pHead2;
}
while (pointer1 != null && pointer2 != null) {
if (more > 0) {
pointer1 = pointer1.next;
more--;
} else {
if (pointer1 == pointer2) {
return pointer1;
}
pointer1 = pointer1.next;
pointer2 = pointer2.next;
}
}
return pointer1;
}
7. 一個鏈表中包含環,請找出該鏈表的環的入口結點。
設置三個指針,一個指針走兩步,第二個指針走一步,第三個指針在表頭。等兩個指針在鏈表中相遇時候,第二個指針和第三個指針同時出發,按一步長走即可,相遇即爲入口結點。
代碼如下:
ListNode EntryNodeOfLoop(ListNode pHead) {
if (pHead == null | pHead.next == null) return null;
ListNode pointer1 = pHead, pointer2 = pHead;
boolean flag = true;
while (flag) {
pointer1 = pointer1.next;
pointer2 = pointer2.next.next;
if (pointer1 == pointer2) {
flag = false;
}
}
pointer1 = pHead;
if (pointer1 == pointer2) {
flag = true;
}
while (!flag) {
pointer1 = pointer1.next;
pointer2 = pointer2.next;
if (pointer1 == pointer2) {
flag = true;
}
}
return pointer2;
}
8. 在一個排序的鏈表中,存在重複的結點,請刪除該鏈表中重複的結點,重複的結點不保留,返回鏈表頭指針。 例如,鏈表1->2->3->3->4->4->5 處理後爲 1->2->5。
遞歸實現,當某結點沒有重複,則此結點指向後續結點的處理返回的鏈表。若有重複,則將結點迭代至最後一個重複結點處,然後後續結點處理返回的鏈表頭結點即頭結點,也就是會略過這個結點。
代碼如下:
ListNode deleteDuplication(ListNode pHead) {
if (pHead == null || pHead.next == null) {
return pHead;
}
ListNode head = pHead;
boolean flag = false;
int val = pHead.val;
while (pHead.next != null && val == pHead.next.val) {
pHead = pHead.next;
flag = true;
}
if (!flag) {
head.next = deleteDuplication(pHead.next);
} else {
head = deleteDuplication(pHead.next);
}
return head;
}