题目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; } } }