Input: (2 -> 4 -> 3) + (5 -> 6 -> 4)
Output: 7 -> 0 -> 8算法
/** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode(int x) { val = x; } * } */ public class Solution { public ListNode addTwoNumbers(ListNode l1, ListNode l2) { int val = (l1.val + l2.val) % 10; int flag = (l1.val + l2.val) / 10; ListNode l3 = new ListNode(val); ListNode res = l3; while (l1.next != null && l2.next != null) { l1 = l1.next; l2 = l2.next; val = (l1.val + l2.val + flag) % 10; flag = (l1.val + l2.val + flag) / 10; ListNode l4 = new ListNode(val); res.next = l4; res = l4; } while (l1.next != null) { l1 = l1.next; val = (l1.val + flag) % 10; flag = (l1.val + flag) / 10; ListNode l4 = new ListNode(val); res.next = l4; res = l4; } while (l2.next != null) { l2 = l2.next; val = (l2.val + flag) % 10; flag = (l2.val + flag) / 10; ListNode l4 = new ListNode(val); res.next = l4; res = l4; } if (flag > 0) { ListNode l4 = new ListNode(flag); res.next = l4; } return l3; } }
這個題目很簡單,就此很少作討論,注意一點就是最後兩個數加完,若是有進位,還須要new個結點出來。數組
因爲單鏈表翻轉時會丟失節點,因此須要把節點保存起來。spa
翻轉單鏈表須要存儲3個節點,分別是當前節點,當前節點的前面節點,當前節點的後繼節點。.net
注意null時的判斷,最後返還時須要把原始節點的尾節點返回。指針
public class Solution { public ListNode reverseList(ListNode head) { ListNode reversedHead = null; ListNode currentNode = head; ListNode prevNode = null; ListNode nextNode = null; while (currentNode != null) { nextNode = currentNode.next; if (nextNode == null) { reversedHead = currentNode; } currentNode.next = prevNode; prevNode = currentNode; currentNode = nextNode; } return reversedHead; } } class ListNode { int val; ListNode next; ListNode(int x) { val = x; } }
For example:
Given 1->2->3->4->5->NULL, m = 2 and n = 4,code
return 1->4->3->2->5->NULL.blog
與翻轉單鏈表不一樣的是,將1->2->3->4->5->NULL轉成1->2<-3<-4<-5->NULL是沒法從尾節點遍歷全部節點的。須要使用另一種思想。排序
總體思想就是頭插法,好比1->2->3->4把2到4翻轉,將結點3插到1和2之間,而後把4再插到1後面。實現翻轉。遞歸
思想很簡單,主要是中間結點不斷再變化位置,因此注意保留不少個位置。leetcode
須要4個變量:待翻轉節點的前一個節點(相似頭節點),待插入節點,待插入節點的下一個節點,插完後的鏈表的最後一個節點。
/** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode(int x) { val = x; } * } */ public class Solution { public ListNode reverseBetween(ListNode head, int m, int n) { ListNode res = new ListNode(0);//必需要有空的頭結點,由於若是相似1-2,要變成2-1,沒辦法把2插到1的前面去 res.next = head; ListNode p = res;//待翻轉的結點的前一個結點,每次都是插在p的後面 for (int i = 0; i < m - 1; i++) { p = p.next; } ListNode l = p.next.next;//待插入結點 ListNode q = null;//下一個待插結點 ListNode d = p.next;//插完後的鏈表的最後一個結點 for (int i = 0; i < n - m; i++) { q = l.next; d.next = q; l.next = p.next; p.next = l; l = q; } return res.next; } }
For example,
Given 1->4->3->2->5->2 and x = 3,
return 1->2->2->4->3->5.
因爲上一題的影響,我第一反應就是頭插法,好比例子中的1->4->3->2,把2插到1的後面變成1->2->4->3,每遇到小的一個就頭插一次。
代碼以下:
/** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode(int x) { val = x; } * } */ public class Solution { public ListNode partition(ListNode head, int x) { if (head == null) { return head; } ListNode res = new ListNode(0); res.next = head; ListNode p = res; while (p != null) { if (p.next == null || p.next.val >= x) { break; } p = p.next; } ListNode d = p.next; ListNode l = d; ListNode b = d; while (l != null) { l = l.next; if (l == null || l.val < x) { break; }else { b = b.next; } } ListNode q = null; if (l != null) { q = l.next; } while (l != null) { if(l.val >= x) { b = l; l = q; if(l != null) { q = l.next; }else { break; } continue; } p.next = l; l.next = d; b.next = q; l = q; if(l != null) { q = l.next; }else { break; } p = p.next; } return res.next; } }
其中如上題設了好多指針,在此解釋一下
p:頭插中的頭
d:大於等於x的第一個結點
b:大於等於x的最後一個結點
l:待插入的結點
q:下一個待判斷的結點
而後對這個複雜的關係畫了半天的圖,終於AC掉了這個問題。
而後一想,分明還有更好的辦法啊。定義兩個指針p1,p2,遍歷一遍鏈表,將小於x的接到p1後面,大於等於x的接到p2後面,最後將p2接到p1後面就行了啊。
代碼以下:
/** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode(int x) { val = x; } * } */ public class Solution { public ListNode partition(ListNode head, int x) { ListNode p1 = new ListNode(0); ListNode p2 = new ListNode(0); ListNode p1tail = p1; ListNode p2tail = p2; while (head != null) { if (head.val < x) { p1tail.next = head; p1tail = p1tail.next; } else { p2tail.next = head; p2tail = p2tail.next; } head = head.next; } p1tail.next = p2.next; p2tail.next = null; return p1.next; } }
這樣代碼簡單多了,思路也更清晰了。
在上面的思路下,這道題目是否是有點像快速排序呢?有關快排或者排序的知識請參kao這裏。選出一個pivot,而後將序列分紅兩邊,一邊比pivot小,一邊比pivot大,而後不斷遞歸。這正是快速排序的思想啊。
該問題其實說明:快速排序對於單鏈表存儲結構仍然使用。
注意:不是全部排序都方便使用鏈表存儲。如堆排序,將不斷的查找數組的n/2和n的位置(父結點與子結點),用鏈表作就不太方便了。
For example,
Given 1->1->2, return 1->2.
Given 1->1->2->3->3, return 1->2->3.
思想很簡單,因爲是排好序的,碰到一個不一樣的值就保存起來,而後比較下一個結點的值是否是和它相同,若是相同則刪掉這個結點,若是不一樣則改變保存起來的值,繼續比較。
代碼以下:
/** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode(int x) { val = x; } * } */ public class Solution { public ListNode deleteDuplicates(ListNode head) { if(head == null) { return head; } ListNode p = head; ListNode p1 = head; int val = head.val; head = head.next; while (head != null) { if(head.val == val) { p1.next = head.next; head = head.next; }else { val = head.val; p1 = head; } } return p; } }
For example,
Given 1->2->3->3->4->4->5, return 1->2->5.
Given 1->1->1->2->3, return 2->3.
思想很簡單,碰到相同的就跳過便可。
代碼以下:
/** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode(int x) { val = x; } * } */ public class Solution { public ListNode deleteDuplicates(ListNode head) { if (head == null) { return head; } ListNode res = new ListNode(0); res.next = head; ListNode p = res;//最後一個不重複的結點 while (head != null) { if (head.next == null || head.val != head.next.val) { p = head; head = head.next; } else { while (head.next != null && head.val == head.next.val) { head = head.next; } head = head.next; p.next = head; } } return res.next; } }
系列: