题目1——链表中倒数最后k个结点
输入一个长度为n的链表,设链表中的元素的值为ai,返回该链表中倒数第k个结点。
如果该链表长度小于k,请返回一个长度为0的链表。
要求:空间复杂度O(n),时间复杂度O(n)。
示例
输入:{1,2,3,4,5}, 2
输出:{4,5}
输入:{2}, 8
输出:{}
解题思路
使用快慢指针,快指针先移动k步,慢指针再从头移动,这时候两个指针同时移动,当快指针到链表的末尾的时候,返回第二个指针即可。
利用栈,首先将原链表的结点全部压入到栈当中,然后再把栈中最上面的k个结点出栈,出栈的结点重新串成一个新的链表。
代码实现
import java.util.*;
/*
* public class ListNode {
* int val;
* ListNode next = null;
* public ListNode(int val) {
* this.val = val;
* }
* }
*/
public class Solution {
public ListNode FindKthToTail (ListNode pHead, int k) {
ListNode dummy = pHead;
ListNode prek = new ListNode(0);
prek = pHead;
for(int i=0;i<k;i++){
if(prek != null)
prek = prek.next;
else return null;
}
while(prek != null){
dummy = dummy.next;
prek = prek.next;
}
return dummy;
}
}
import java.util.*;
/*
* public class ListNode {
* int val;
* ListNode next = null;
* public ListNode(int val) {
* this.val = val;
* }
* }
*/
public class Solution {
public ListNode FindKthToTail (ListNode pHead, int k) {
ListNode res = new ListNode(0);
Stack<ListNode> st = new Stack<ListNode>();
while(pHead != null){
st.push(pHead);
pHead = pHead.next;
}
for(int i=0;i<k;i++){
if(st.isEmpty())
return null;
ListNode tmp = st.pop();
if(res.next == null){
res.next = tmp;
}else{
tmp.next = res.next;
res.next = tmp;
}
}
return res.next;
}
}
题目2——两个链表的第一个公共结点
输入两个无环的单向链表,找出它们的第一个公共结点,如果没有公共结点则返回空。
要求:空间复杂度O(1),时间复杂度O(n)。
解题思路
利用双指针,若两个链表存在公共结点,则两个指针以同样的速度走完同样的长度(链表1+链表2),一定会相遇;而没有公共结点的时候,两个指针都会走到终点,此时都为空。
或者是利用集合,将第一个链表中的所有结点存放到集合中,然后遍历第二个链表,判断其是否存在集合中,如果存在,则返回这个结点,否则遍历后没有找到,则说明没有相交,返回null即可。
代码实现
import java.util.*;
/*
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}*/
public class Solution {
public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
if(pHead1 == null || pHead2 == null)
return null;
ListNode p1 = pHead1;
ListNode p2 = pHead2;
while(p1 != p2){
p1 = (p1 == null)?pHead2:p1.next;
p2 = (p2 == null)?pHead1:p2.next;
}
return p1;
}
}
import java.util.*;
/*
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}*/
public class Solution {
public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
if(pHead1 == null || pHead2 == null)
return null;
ListNode p1 = pHead1;
ListNode p2 = pHead2;
Set<ListNode> set = new HashSet<ListNode>();
while(p1 != null){
set.add(p1);
p1 = p1.next;
}
while(p2 != null){
if(!set.contains(p2)){
p2 = p2.next;
}else
return p2;
}
return null;
}
}
题目3——二叉搜索树的最近公共祖先
给定一个二叉搜索树,找到该树种两个指定结点的最近公共祖先。
最近公共祖先定义:对于有根树T的两个结点p、q,最近公共祖先LCA(T,p,q)表示一个结点x,满足x是p和q的祖先且x的深度尽可能大。在这里,一个结点也可以是它自己的祖先。
示例
输入:{7,1,12,0,4,11,14,#,#,3,5},1,12
输入:7
解题思路
首先检查空结点,空树没有公共祖先;
比较两个结点的值,若都小于根结点,则p,q结点都在该结点的左侧,公共祖先在左子树中,递归进入左子树;
若都大于根结点,则公共祖先都在右子树中,递归进入右子树;
否则,返回最近公共祖先即为根结点。
找到两个结点的路径,然后将路径中的结点存放到数组当中,比较两个数组,最后一个相等的元素就是最近的公共祖先。
寻找路径时,根据二叉搜索树的性质,当前结点的值比目标大,则进入左子树,否则进入右子树。
代码实现
import java.util.*;
/*
* public class TreeNode {
* int val = 0;
* TreeNode left = null;
* TreeNode right = null;
* public TreeNode(int val) {
* this.val = val;
* }
* }
*/
public class Solution {
public int lowestCommonAncestor (TreeNode root, int p, int q) {
if(root == null)
return -1;
if(p<root.val && q<root.val)
return lowestCommonAncestor(root.left,p,q);
if(p>root.val && q>root.val)
return lowestCommonAncestor(root.right,p,q);
return root.val;
}
}
import java.util.*;
/*
* public class TreeNode {
* int val = 0;
* TreeNode left = null;
* TreeNode right = null;
* public TreeNode(int val) {
* this.val = val;
* }
* }
*/
public class Solution {
public ArrayList<Integer> getPath(TreeNode root,int target){
ArrayList<Integer> path = new ArrayList<Integer>();
while(root.val != target){
path.add(root.val);
if(target<root.val)
root = root.left;
else
root = root.right;
}
path.add(root.val);
return path;
}
public int lowestCommonAncestor (TreeNode root, int p, int q) {
ArrayList<Integer> path_p = getPath(root,p);
ArrayList<Integer> path_q = getPath(root,q);
int res = 0;
for(int i=0;i<Math.min(path_p.size(),path_q.size());i++){
int x = path_p.get(i);
int y = path_q.get(i);
if(x == y)
res = path_p.get(i);
else
break;
}
return res;
}
}