目錄
9.convert-sorted-list-to-binary-search-tree
10.remove-nth-node-from-end-of-list
1.linked-list-cycle
題目:判斷給定的鏈表中是否有環,滿足不使用額外的空間
分析:利用快慢指針,如果快慢指針能相遇則說明有環
public boolean hasCycle(ListNode head) {
ListNode low = head;
ListNode quick = head;
while(quick != null && quick.next != null){
quick = quick.next.next;
low = low.next;
if(low == quick)
return true;
}
return false;
}
2.linked-list-cycle-ii
題目:對於一個給定的鏈表,返回環的入口節點,如果沒有環,返回null
分析:見劍指offer面試題23 https://blog.csdn.net/Nibaby9/article/details/104050540
3.partition-list
題目:給出一個鏈表和一個值x,以x爲參照將鏈表劃分成兩部分,使所有小於x的節點都位於大於或等於x的節點之前。兩個部分之內的節點之間要保持的原始相對順序。例如:給出1->4->3->2->5->2和x = 3,返回1->2->2->4->3->5.
分析:新建立兩個結點,將小於x的結點與大於等於x的結點分別插到這兩個結點之後,形成兩條鏈表,最後將兩條鏈表連起來即可。
public ListNode partition(ListNode head, int x) {
ListNode head1 = new ListNode(0);
ListNode head2 = new ListNode(0);
ListNode cur = head,cur1 = head1,cur2 = head2;
while(cur != null){
if(cur.val < x){
cur1.next = cur;
cur1 = cur1.next;
}
else{
cur2.next = cur;
cur2 = cur2.next;
}
cur = cur.next;
}
cur1.next = head2.next;
cur2.next = null;
return head1.next;
}
4.reverse-linked-list-ii
題目:將一個鏈表m位置到n位置之間的區間反轉,要求使用原地算法,並且在一次掃描之內完成反轉。例如:給出的鏈表爲1->2->3->4->5->NULL, m = 2 ,n = 4,返回1->4->3->2->5->NULL。注意:給出的m,n滿足以下條件:1 ≤ m ≤ n ≤ 鏈表長度
分析:定義兩個指針,指針pre指向鏈表開始反轉的前一個位置,指針start指向鏈表反轉的第一個位置。每次刪除start的後一個節點,再該結點插入pre後面,需刪除n-m次即可。注意:鏈表的頭結點可能會發生變化,需要創建一個新節點來指向鏈表的頭結點。
翻轉鏈表類似題見劍指offer面試題24 https://blog.csdn.net/Nibaby9/article/details/104050540
public ListNode reverseBetween(ListNode head, int m, int n){
ListNode preHead = new ListNode(0);//方便返回鏈表頭結點,修改後的頭結點有可能不是head
preHead.next = head;//勿漏
ListNode pre = preHead;
ListNode start = head;
for(int i = 1;i < m;i++){
pre = start;
start = start.next;
}
for(int i = 1;i <= n - m;i++) {//需要刪n-m次
ListNode temp = start.next;
start.next = temp.next;
temp.next = pre.next;
pre.next = temp;
}
return preHead.next;
}
5.reverse-nodes-in-k-group
題目:將給出的鏈表中的節點每k個一組翻轉,返回翻轉後的鏈表。如果鏈表中的節點數不是k的倍數,將最後剩下的節點保持原樣。你不能更改節點中的值,只能更改節點本身。只允許使用常數級的空間。例如:給定的鏈表是1->2->3->4->5,對於 k = 2, 你應該返回 2->1->4->3->5;對於 k = 3, y你應該返回 3->2->1->4->5
分析:遞歸。將前k個節點與剩下節點斷開,翻轉前k個節點,遞歸求解剩下節點,再將兩條鏈表合併即可。
public ListNode reverseKGroup(ListNode head, int k) {
ListNode end = head;
int index = 1;
while(index < k && end != null){
end = end.next;
index++;
}
if(end == null || index < k)
return head;
ListNode head2 = end.next;
end.next = null;
head2 = reverseKGroup(head2,k);
ListNode head1 = reverse(head);
head.next = head2;
return head1;
}
private ListNode reverse(ListNode head) {
ListNode cur = head,pre = null;
while(cur != null){
ListNode temp = cur.next;
cur.next = pre;
pre = cur;
cur = temp;
}
return pre;
}
6.rotate-list
題目:將給定的鏈表向右轉動k個位置,k是非負數。例如:給定1->2->3->4->5->null , k=2,返回4->5->1->2->3->null。
分析:特別注意k可能大於鏈表長度!!!因此k = k%len。將尾結點next指針指向首節點,形成一個環,接着往後跑len-k步,就是所需鏈表的尾結點,從這斷開鏈表即可。
public ListNode rotateRight(ListNode head, int n) {
if (head == null || head.next == null || n == 0)
return head;
int len = 1;
ListNode tail = head;
while(tail.next != null){
len++;
tail = tail.next;
}
tail.next = head;//首尾相連形成環
for(int i = 0;i < len - n % len;i++){//注意n有可能大於鏈表長度
tail = tail.next;
}
head = tail.next;
tail.next = null;
return head;
}
7.reorder-list
題目:將給定的單鏈表L: L 0→L 1→…→L n-1→L n,重新排序爲: L 0→L n →L 1→L n-1→L 2→L n-2→…要求使用原地算法,並且不改變節點的值。例如:對於給定的單鏈表{1,2,3,4},將其重新排序爲{1,4,2,3}.
分析:將鏈表分成兩半,然後將後半部分翻轉,最後拼接兩個鏈表即可。
public void reorderList(ListNode head) {
if(head == null)
return;
//將鏈表從中間斷開
ListNode mid = findMid(head);
ListNode head2 = mid.next;
mid.next = null;
//將鏈表的前半部分和反轉後的後半部分合並
ListNode cur1 = head,cur2 = reverse(head2);
while(cur1 != null && cur2 != null){
ListNode temp1 = cur1.next;
ListNode temp2 = cur2.next;
cur1.next = cur2;
cur2.next = temp1;
cur1 = temp1;
cur2 = temp2;
}
}
private ListNode reverse(ListNode head) {
ListNode pre = null,cur = head;
while(cur != null){
ListNode temp = cur.next;
cur.next = pre;
pre = cur;
cur = temp;
}
return pre;
}
private ListNode findMid(ListNode head) {
ListNode low = head,fast = head;
while(fast != null && fast.next != null){
low = low.next;
fast = fast.next.next;
}
return low;
}
8.swap-nodes-in-pairs
題目:將給定的鏈表中每兩個相鄰的節點交換一次,返回鏈表的頭指針。例如,給出1->2->3->4,你應該返回鏈表2->1->4->3。你給出的算法只能使用常量級的空間。你不能修改列表中的值,只能修改節點本身。
分析:遞歸求解即可。
public ListNode swapPairs(ListNode head) {
if(head == null || head.next == null)
return head;
ListNode temp = head.next;
head.next = swapPairs(temp.next);
temp.next = head;
return temp;
}
9.convert-sorted-list-to-binary-search-tree
題目:給定一個單鏈表,其中的元素按升序排序,請將它轉化成平衡二叉搜索樹(BST)
分析:先利用快慢指針找到單鏈表的中間節點,然後以該節點爲根結點,再把原鏈表斷開,分爲前後兩個鏈表,遞歸調用原函數,分別爲根結點的左右子樹。注意參數的設計,傳遞的是鏈表的第一個結點和最後一個節點的next。
public TreeNode sortedListToBST(ListNode head) {
return toBST(head,null);
}
private TreeNode toBST(ListNode head, ListNode tail) {
if(head == tail)
return null;
ListNode quick = head;
ListNode low = head;
while(quick != tail && quick.next != tail){
low = low.next;
quick = quick.next.next;
}
TreeNode root = new TreeNode(low.val);
root.left = toBST(head,low);
root.right = toBST(low.next,tail);
return root;
}
10.remove-nth-node-from-end-of-list
題目:給定一個鏈表,刪除鏈表的倒數第n個節點並返回鏈表的頭指針。例如, 給出的鏈表爲:1->2->3->4->5, n= 2.↵↵ 刪除了鏈表的倒數第n個節點之後,鏈表變爲1->2->3->5.備註:題目保證n一定是合法的;請嘗試只用一步操作完成該功能
分析:刪除倒數第n個節點需先找出倒數第n+1個節點。倒數數第n+1個節點也就是第len-n個節點,採用快慢指針,快指針先走出n步,隨後兩個指針同時前進,當快指針到達鏈表尾部時,慢指針剛好到達倒數第n+1個節點的位置。注意刪除節點爲鏈表頭結點的情況。類似題見劍指offer面試題22 https://blog.csdn.net/Nibaby9/article/details/104050540
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode preHead = new ListNode(0);
preHead.next = head;
ListNode quick = preHead;
ListNode slow = preHead;
for(int i = 0;i < n;i++)
quick = quick.next;
while(quick.next != null){
slow = slow.next;
quick = quick.next;
}
slow.next = slow.next.next;
return preHead.next;
}