題目java
輸入一個鏈表,輸出該鏈表中倒數第k個結點。
思路數組
1.首先想到的是走到鏈表的尾端,再由尾端回溯k步。但是鏈表的節點定義看出這是單向鏈表,結點只有從前日後的指針,所以不能這樣走。this
2.只能從頭節點開始遍歷鏈表。那麼咱們能夠先獲取鏈表的結點數,就能夠計算從前日後是須要走多少步了。可是這樣須要遍歷兩次鏈表spa
3.爲了實現只遍歷一次鏈表,咱們仍是像以前翻轉數組同樣,設立兩個指針。第一個指針從鏈表的頭指針開始遍歷向前走k-1,第二個指針始終指向頭結點。當第一個指針指向k個結點的時候,兩個指針同時向前遍歷,這樣確保兩個指針距離爲k。那麼當第一個指針指向末尾結點時,第二個指針指向的就是倒數第k個結點。指針
4.而且須要注意潛在崩潰的風險。當輸入的head爲空指針時,代碼會試圖訪問空指針的內存空間;輸入的鏈表結點數小於k,for循環中會在鏈表上向前走k-1步,一樣會形成空指針;當k是unsigned int型時,輸入的參數k爲0,此時for循環的k獲得的不是-1,而是0xFFFFFFFF(4294967295),執行次數會很是很是大,形成程序崩潰。code
解法blog
/* public class ListNode { int val; ListNode next = null; ListNode(int val) { this.val = val; } }*/ public class Solution { public ListNode FindKthToTail(ListNode head,int k) { if(head == null) return null; ListNode P1=head; while(P1!=null && k-->0) P1=P1.next; //若是k大於鏈表的長度 if(k>0){ return null; } ListNode P2=head; while(P1!=null){ P1=P1.next; P2=P2.next; } return P2; } }
題目遞歸
輸入一個鏈表,反轉鏈表後,輸出新鏈表的表頭。
思路內存
1.反轉後鏈表的頭結點就是原始鏈表的尾節點,即next爲NULL的結點。io
2.一樣能夠採用遞歸,使當前head的next指向null,不斷反轉。
3.或者採用頭插法。構建一個新的指針用來指向
解法
/* public class ListNode { int val; ListNode next = null; ListNode(int val) { this.val = val; } }*/ public class Solution { public ListNode ReverseList(ListNode head) { if(head == null || head.next == null) return head; ListNode next=head.next; head.next=null; ListNode newHead=ReverseList(next); next.next=head; return newHead; }
public
ListNode ReverseList(ListNode head) {
ListNode newList =
new
ListNode(-
1
);
while
(head !=
null
) {
ListNode next = head.next;
head.next = newList.next;
newList.next = head;
head = next;
}
return
newList.next;
}
}
題目
輸入兩棵二叉樹A,B,判斷B是否是A的子結構。(ps:咱們約定空樹不是任意一個樹的子結構)
思路
判斷A中有一部分子樹的結構與B是同樣的,則採用遞歸。
1.在樹A中找到與B的根結點值相同的結點R
2.判斷樹A中以結點R爲根結點的子樹是否包含與B同樣的結構。根據根結點找到相同結構的部分,再往下比較
解答
/** public class TreeNode { int val = 0; TreeNode left = null; TreeNode right = null; public TreeNode(int val) { this.val = val; } } */ public class Solution { public boolean HasSubtree(TreeNode root1,TreeNode root2) { boolean result=false; //檢查空指針 if(root1!=null && root2!=null){ //當A的某一結點的值和樹B的頭結點值相同,則作第二步判斷 if(root1.val == root2.val) //判斷樹A中以R爲根結點的子樹是否是和樹B具備相同的結構 result = DoesTree1HaveTree2(root1, root2); //若是當前根節點不相同,就看root1的左結點和root2的根節點比較。就是低一層比較 if(!result) result=HasSubtree(root1.left, root2); if(!result) result=HasSubtree(root1.right, root2); } return result; } public boolean DoesTree1HaveTree2(TreeNode root1, TreeNode root2){ //遞歸的終止條件:即到達了樹A或樹B的葉結點 if(root2 == null) return true; if(root1 == null) return false; //若結點R的值和樹B的根結點不相同,那麼它們確定不具備相同的結點 if(root1.val != root2.val) return false; //若是值相同,那麼遞歸判斷它們各自的左右結點值是否是相同 return DoesTree1HaveTree2(root1.left, root2.left) && DoesTree1HaveTree2(root1.right, root2.right); } }
題目
輸入兩個單調遞增的鏈表,輸出兩個鏈表合成後的鏈表,固然咱們須要合成後的鏈表知足單調不減規則。
思路
1.鏈表的合併過程以下,從合併兩個鏈表的頭結點開始,當鏈表1的頭結點的值小於鏈表2的頭結點值,所以鏈表1的頭結點將爲合併後鏈表的頭結點。剩餘結點中,鏈表2的頭結點值小於鏈表1的頭結點的值,所以鏈表2的頭結點是剩餘結點的頭結點,把這個結點和以前合併好的鏈表的尾節點連接起來。不斷比較兩個鏈表的頭結點的值。
2.爲了防止訪問空指針指向的內存空間引發的崩潰,須要處理當兩個鏈表爲空鏈表時的結果,當都爲空鏈表時,合併的結果就是空鏈表。
解法
/* public class ListNode { int val; ListNode next = null; ListNode(int val) { this.val = val; } }*/ public class Solution { public ListNode Merge(ListNode list1,ListNode list2) { if(list1==null) return list2; if(list2==null) return list1; if(list1.val<=list2.val){ list1.next=Merge(list1.next,list2); return list1; } else{ list2.next=Merge(list1,list2.next); return list2; } } }