剑指offer题解8
34 两个链表的第一个公共结点
题目描述
输入两个链表,找出它们的第一个公共结点。
分析:
- 方法一:使用Set,记录是否出现过该节点
- 方法二:因为如果有公共的节点,那么从这个节点之后,这两个链表共享一系列的节点;计算出两个链表的长度,然后长的链表先走一段路程,使得两个链表长度一样,那么从这个时候开始他么一起遍历,第一个相同的节点就是公共节点。
- 方法三:假如p1由x,z组成,p2由y,z组成,z为共享的部分,如果有一种方法,使得两个链表每次走一步,都走x+y+z步,而且停留在z的开始的位置,那么我们就找到了这个节点。方法:当一个节点到了尾部,那么它就从另一个链表开始的位置开始继续遍历即可。
//方法一:
public class Solution {
public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
ListNode p1=pHead1,p2=pHead2;
HashSet<ListNode> set=new HashSet<>();
while(p1!=null||p2!=null){
if(p1!=null){
if(set.contains(p1)){
return p1;
}
set.add(p1);
p1=p1.next;
}
if(p2!=null){
if(set.contains(p2)){
return p2;
}
set.add(p2);
p2=p2.next;
}
}
return null;
}
}
//方法二
public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
ListNode p1=pHead1,p2=pHead2;
int len1=len(p1);
int len2=len(p2);
int offset=Math.abs(len1-len2);
if(len1>len2){
p1=walk(offset,p1);
}else{
p2=walk(offset,p2);
}
while(p1!=p2){
p1=p1.next;
p2=p2.next;
}
return p1;
}
private static ListNode walk(int offset,ListNode list){
while(offset--!=0){
list=list.next;
}
return list;
}
private static int len(ListNode list){
int len=0;
while(list!=null){
len++;
list=list.next;
}
return len;
}
//方法三
public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
ListNode p1=pHead1,p2=pHead2;
while(p1!=p2){
p1= p1==null?pHead2:p1.next;
p2= p2==null?pHead1:p2.next;
}
return p1;
}
35 数字在排序数组中出现的次数
题目描述
统计一个数字在排序数组中出现的次数。
分析:
- 方法一:找到这个数,然后向两边扩展,最坏复杂度O(n)
- 方法二:找到第一个出现的位置,找到最后一个出现的位置,都使用二分法,最坏复杂度O(logN)
//方法一
public class Solution {
public int GetNumberOfK(int [] array , int k) {
int l=0,r=array.length,mid=0,count=0;
while(l<r){
mid=(r-l)/2+l;
int curr=array[mid];
if(curr==k){
break;
}else if(curr>k){
r=mid-1;
}else{
l=mid+1;
}
}
if(array.length==0||array[mid]!=k){
return 0;
}
int p=mid;
while(p>=0&&array[p--]==k){
count++;
}
p=mid+1;
while(p<array.length&&array[p++]==k){
count++;
}
return count;
}
}
//方法二
public class Solution {
public int GetNumberOfK(int [] array , int k) {
if(array==null||array.length==0){
return 0;
}
int l=getFirstK(array,0,array.length-1,k);
int r=getLastK(array,0,array.length-1,k);
if(l==-1||r==-1){
return 0;
}
return r-l+1;
}
private static int getFirstK(int[] array,int l,int r,int k){
while(l<=r){
int mid=(l+r)/2;
if(array[mid]>k){
r=mid-1;
}else if(array[mid]<k){
l=mid+1;
}else{
if(mid<=0||array[mid-1]!=k){
return mid;
}else{
r=mid-1;
}
}
}
return -1;
}
private static int getLastK(int[] array,int l,int r,int k){
while(l<=r){
int mid=(l+r)/2;
if(array[mid]>k){
r=mid-1;
}else if(array[mid]<k){
l=mid+1;
}else{
if(mid>=array.length-1||array[mid + 1] != k){
return mid;
}else{
l=mid+1;
}
}
}
return -1;
}
}
36 二叉树的深度
题目描述
输入一棵二叉树,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。
分析:遍历即可
public class Solution {
public int TreeDepth(TreeNode root) {
if(root==null){
return 0;
}
int lDepth=TreeDepth(root.left);
int rDepth=TreeDepth(root.right);
return Math.max(lDepth,rDepth)+1;
}
}
37 判断是否是是平衡二叉树
题目描述
输入一棵二叉树,判断该二叉树是否是平衡二叉树。
分析:递归判断左右节点的深度即可
public class Solution {
private boolean isBalance=true;
public boolean IsBalanced_Solution(TreeNode root) {
getDeep(root);
return isBalance;
}
private int getDeep(TreeNode root){
if(root==null){
return 0;
}
int lDeep=getDeep(root.left)+1;
int rDeep=getDeep(root.right)+1;
if(Math.abs(lDeep-rDeep)>1){
isBalance=false;
}
return Math.max(lDeep,rDeep);
}
}