剑指offer 36-40

36.两个链表的第一个公共结点

输入两个链表,找出它们的第一个公共结点。

拿到这个题,试想一下,如果两个链表的长度一样,应该怎么做,当然就是两个链表从头结点开始同时往后遍历,找到第一个相同的结点即可。
那么上升到更一般的情况下,两个链表长度不相等,应该怎么做,单向链表是不可逆的,因此我们没法从后往前找第一个公共结点。我们可以仿照两个链表长度相同到的情况下进行求解,怎么让两个链表长度相同呢,就是分别求出两个链表的长度,然后让长的那个链表先往后走两个链表之间的差值的长度即可。
代码如下

public class Solution {
    public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
        if(pHead1==null||pHead2==null){
            return null;
        }
        ListNode cur1 = pHead1;
        ListNode cur2 = pHead2;
        //用两个数字分别记录两个链表的长度
        int cnt1 = 0,cnt2 = 0;
        while(cur1!=null){
            cnt1++;
            cur1 = cur1.next;
        }
        while(cur2!=null){
            cnt2++;
            cur2 = cur2.next;
        }
        cur1 = pHead1;
        cur2 = pHead2;
        //如果链表1长,就让链表1走cnt1-cnt2的长度
        //如果链表2长,就让链表2走cnt2-cnt1的长度
        int cnt = 0;
        if(cnt1<cnt2){
            while(cnt<cnt2-cnt1){
                cur2 = cur2.next;
                cnt++;
            }
        }else{
            while(cnt<cnt1-cnt2){
                cur1 = cur1.next;
                cnt++;
            }
        }
        //两个链表的指针同时向后走,碰到第一个相等的结点就是第一个公共结点
        while(cur1!=null&&cur2!=null){
            if(cur1==cur2){
                return cur1;
            }else{
                cur1 = cur1.next;
                cur2 = cur2.next;
            }
        }
        return null;
        
    }
}

37.数字在排序数组中出现的次数

统计一个数字在排序数组中出现的次数。

最简单直观的方法当然是按顺序统计,这样的时间复杂度是O(n)
代码如下

public class Solution {
    //private int cnt = 0;
    public int GetNumberOfK(int [] array , int k) {
        if(array.length<=0){
            return 0;
        }
        int cnt = 0;
        for(int num:array){
            cnt = num==k?cnt+1:cnt;
        }
        return cnt;
    }
}

但是既然题目中已经给了排序这个信息,我们就应该利用好排序这个信息,即用BinarySearch进行寻找第一个K出现的位置和第一个大于K的数出现的位置。
在使用二分查找的时候,我们需要明白几点:
1.二分查找的原理就是"逼近",当mid指向的数大于等于target时,证明target在前半段数组中;反之target在后半段数组中,直到低位指针与高位指针重合;
2.如果我们要找的数不在数组中,可能存在两种情况

1.target夹在数组中间,例如target=4,array={1,3,5,7,9};这种情况下试想,
我们通过逼近的方法可以“知道”4在3的后面,而7,9显然是大于4的,所以最后夹在中间的只有5
这里可以延伸为我们在数组中寻找target时,如果target不存在,则会找到第一个大于target的数;
2.target大于数组中全部的数,例如target=6,array={1,2,3,4,5},
我们最好在写代码的时候就将high定义为array.length,这样通过逼近的方法,最后l和h重叠的时候就出界了,这样方便判断;

根据以上可以写出如下流程的代码

1.对target进行二分查找,找到target出现的第一个位置;
2.对target+1进行二分查找,这里的意思是找到第一个大于等于target+1的元素,类似于放缩发也就找到了第一个大于target的元素;
3.对l进行判断是不是上面提到的两种不存在的情况,对于第一种情况需要判断array[first]和k是否相等,对于第二种情况需要判断first是否出界了,满足以上两者之一的,都需要判定target不存在数组中,返回0.

代码如下

public class Solution {
    public int GetNumberOfK(int [] array , int k) {
        if(array.length<=0){
            return 0;
        }
        //对k进行二分查找,找到k第一次出现的位置
        int first = binarysearch(array,k);
        //对k+1进行二分查找,找到大于等于K+1的数,即大于K的数第一次出现的位置;
        int last = binarysearch(array,k+1);
        //满足target夹在数组中某两个数中间或target大于数组中全部数情况之一的,需要返回0
        return (first==array.length||array[first]!=k)?0:last-first;
    }
    //定义简单二分查找函数
    private int binarysearch(int [] array,int k){
        int l = 0,h = array.length;
        while(l<h){
            int m = (l+h)/2;
            if(array[m]>=k){
                h = m;
            }else{
                l = m+1;
            }
        }
        return l;
        
    }
}

二叉树的深度

输入一棵二叉树,求该树的深度。
从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。

这个题思路倒是简单,就用一个变量来保存当前最大深度,
然后用深度遍历的方法统计各条路线的长度,然后与这个最大深度进行比较取大者,最后输出最大值。
代码如下

public class Solution {
    private int depth = 0;
    public int TreeDepth(TreeNode root) {
        if(root==null){
            return 0;
        }
        //这里要注意不要采坑!!!
        //我们往下进行递归的时候会使计数+1
        //以单个根节点为例,左右结点为空,但是计数+1了,层数为0+1=1,这才是符合实际情况到的
        //所以在入口的时候传递的初始层数应该为0
        find_depth(root,0);
        return depth;
    }
    //对二叉树进行深度遍历
    public void find_depth(TreeNode root,int cnt){
        //当递归到结点为null的时候,将当前的cnt与depth进行比较取大者
        if(root==null){
            depth = cnt>depth?cnt:depth;
            return;
        }
        //对左右子树进行递归处理
        find_depth(root.left,cnt+1);
        find_depth(root.right,cnt+1);
    }
}

39.平衡二叉树

输入一棵二叉树,判断该二叉树是否是平衡二叉树。

这个题的思路还是判断左右子树的高度差是否小于1,我们可以采用这样的方式,即初始化一个布尔变量为true,全局中只要出现一个位置不满足平衡二叉树的条件,就会使这个变量被赋值为false,如果全局都满足平衡二叉树,最后的输出也就是true;同时,在计算树的深度的时候要学会通过递归返回值,具体步骤如下

1.初始化一个全局布尔变量boolean res = true;
2.构建一个整型返回值的函数用来计算树的高度,注意这个函数既承担了在递归中不断计算树的深度的任务,又承担着判断各子树是否为平衡二叉树,当然只要判定一次不为平衡二叉树,其它也就无所谓了。

有了这个思路,代码如下

public class Solution {
    //初始化一个全局布尔变量
    private boolean res = true;
    public boolean IsBalanced_Solution(TreeNode root) {
        //height函数无需返回值,因为只需要在当中判定res是否会变成false即可
        height(root);
        return res;
    }
    private int height(TreeNode root){
        //如果结点为空则返回0,这既是对根节点的判定,也是一个递归计算深度的初始值
        if(root==null){
            return 0;
        }
        //对左右子树进行递归
        int left = height(root.left);
        int right = height(root.right);
        if(Math.abs(left-right)>1){
            res = false;
        }
        //这里承担着一层层往上递归树的深度的任务
        //可以这样看,root的深度是多少?是1加上左子树的深度和右子树的深度中的大者
        //那么左子树深度left和右子树深度right是多少呢?
        //就是又要用到这个height函数来求解了,left = height(root.left);right=height(root.right);
        //当递归到叶子结点的时候,可以看到左右都为null,即叶子结点的深度为1,这也是一层层往上递归的
        return 1+Math.max(left,right);
    }
}

40.数组中只出现一次的数字

一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。

之前做的简单难度的是找出一个只出现一次的数字,这次要找两个,要学会将复杂问题拆分成简单的子问题来求解,如果我们能根据某些特征将这些数字分成两组,第一组只包含第一个数,第二组只包含第二个数,然后再用只出现一次的一个数这个思路来求解不就行了吗?
假设这两个只出现一次的数为a,b我们对数组中所有的数求异或,最后得到的结果就是a^b,异或异或顾明思意这个结果肯定会包含1,因为a,b肯定是不相等,我们找到第一个为1的位,例如00100这个数,整个数组就被划分成两个部分了,1.该位为1;2该位不为1;
该位为1的数与上00100肯定不为0,该位为0的数与上00100肯定为0
按照这个思路,流程如下

1.求出这两个数相异或的结果
2.求出这个结果中第一位为1的这个数
3.根据这个判定条件,分别不同条件下的数不断求异或运算,得到最终的两个数

代码如下

//num1,num2分别为长度为1的数组。传出参数
//将num1[0],num2[0]设置为返回结果
public class Solution {
    public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) {
        int diff = 0;
        for(int num:array){
            diff ^= num;
        }
        //找到第一个不为1的数
        //负数的二进制是取反加1
        //以diff=10100为例,-diff = 01011+1=01100
        //10100&01100=00100,正好就是我要求的
        diff &= -diff;
        for(int num:array){
            //这里就是分为了两个元素区,第一个为在该位上为0,则与diff后全部为0,我们异或所有的这些数即可
            //相反得到到的就是另外一个数
            if((num&diff)==0){
                num1[0] ^=num;
            }else{
                num2[0] ^=num;
            }
        }
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 221,695评论 6 515
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,569评论 3 399
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 168,130评论 0 360
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,648评论 1 297
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,655评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,268评论 1 309
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,835评论 3 421
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,740评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,286评论 1 318
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,375评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,505评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,185评论 5 350
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,873评论 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,357评论 0 24
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,466评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,921评论 3 376
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,515评论 2 359

推荐阅读更多精彩内容

  • 基本概念 链表的含义: 链表是一种用于存储数据集合的数据结构,具有以下属性 相邻元素之间通过指针相连 最后一个元素...
    古剑诛仙阅读 1,010评论 0 3
  • 1. 找出数组中重复的数字 题目:在一个长度为n的数组里的所有数字都在0到n-1的范围内。数组中某些数字是重复的,...
    BookThief阅读 1,775评论 0 2
  • 链表 记录《剑指offer》中所有关于链表的题目,以及LeetCode中的相似题目 相关题目列表 题目 链表是面试...
    wenmingxing阅读 1,172评论 0 11
  • 大学的时候不好好学习,老师在讲台上讲课,自己在以为老师看不到的座位看小说,现在用到了老师讲的知识,只能自己看书查资...
    和珏猫阅读 1,447评论 1 3
  • 转载请注明出处:http://www.jianshu.com/p/c65d9d753c31 在上一篇博客《数据结构...
    Alent阅读 3,513评论 4 74