天天看点

剑指offer/36-40

文章目录

    • 36、两个链表第一个公共节点
    • 37、统计一个数字在升序数组中出现的次数
    • 38、二叉树的深度
    • 39、平衡二叉树
    • 40、数组中只出现一次的数

36、两个链表第一个公共节点

题目描述

输入两个链表,找出它们的第一个公共结点。(注意因为传入数据是链表,所以错误测试数据的提示是用其他方式显示的,保证传入数据是正确的)

思路:

对于两个这样的序列:

0-1-2-3-4-5-null
a-b-4-5-null
           

他们的公共点后的长度必定是相同的。

也就是说

4-5-null

这后两个节点是共同的。

那么可以这么推理:

0-1-2-3-4-5-null a-b-4-5-null

a-b-4-5-null 0-1-2-3-4-5-null

的长度是相同的,且他们的节点都是

4-5-null

,且到这个公共节点的最后一个节点的距离相同,都是第九个。

链接:https://www.nowcoder.com/questionTerminal/6ab1d9a29e88450685099d45c9e31e46?answerType=1&f=discussion
来源:牛客网

    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.next;
            p2 = p2.next;
            if (p1 != p2 && p1 == null) {
                p1 = pHead2;
            }
            if (p1 != p2 && p2 == null) {
                p2 = pHead1;
            }
        }
        return p1;
    }
           

37、统计一个数字在升序数组中出现的次数

题目描述:

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

显然是利用二分查找。因为有序,所以目标值target如果有多个,肯定是连在一起。又已知我们可以在有序数组中查找任意一个值,因此我们可以先查找目标范围的下界和上界。

下界定义为:如果存在目标值,则指向第一个目标值,否则,如果不存在, 则指向大于目标值的第一个值。

上界定义为:不管目标值存在与否,都指向大于目标值的第一个值。

package M36TO40;

public class SoluGetNumberOfK {
    public int GetNumberOfK(int [] array , int k) {
        if (array ==null || array.length==0) return 0;
        int lowIndex = lowerBound(array,k);
        int upperIndex = upperBound(array,k);
        return upperIndex-lowIndex;
    }
    //这里左边界和右边界,关键是看当等于target时,是l = mid + 1还是r = mid-1
    private int upperBound(int[] array,int val){
        int l = 0,r = array.length-1,mid;
        while (l<=r){
            mid = (l+r)/2;
            //要找的值比中间值大则,值位于中间点右边,l= mid +1;,直到找到大于val的第一个值
            if (array[mid]<=val){
                l = mid + 1;
            //要找的值比中间值小则,值位于中间点左边,r= mid-1;
            }else{
                r = mid-1;
            }
        }
        return l;
    }
    private int lowerBound(int[] array,int val){
        int l = 0,r = array.length-1,mid;
        while (l<=r){
            mid=(l+r)/2;
            //与上面的区别是,即使相等也向右找知道找最小的val的值
            if (array[mid]<val){
                l = mid +1;
            }else{
                r = mid-1;
            }
        }
        return l;
    }

}

           

38、二叉树的深度

题目描述

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

package M36TO40;

import M16TO20.TreeNode;
import java.util.LinkedList;
import java.util.Queue;

public class SoluTreeDepth {
    public int TreeDepth(TreeNode root){
        if (root == null) return 0;

        //用层次遍历(广度优先遍历)
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        int depth = 0;
        while (!queue.isEmpty()){
            for (int i = 0;i< queue.size();i++){
                TreeNode node = queue.poll();
                if (node.left !=null) queue.offer(node.left);
                if (node.right !=null) queue.offer(node.right);
            }
            depth++;
        }
        return depth;
    }
}
           

39、平衡二叉树

题目描述

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

在这里,我们只需要考虑其平衡性,不需要考虑其是不是排序二叉树

package M36TO40;

import M16TO20.TreeNode;

public class SoluIsBalanced_Solution {
    public int depth(TreeNode root){
        if (root==null) return 0;
        int left = depth(root.left);
        if (left==-1) return -1;//如果发现子树不平衡之后就没有必要进行下面的高度的求解了
        int right = depth(root.right);
        if (right==-1) return -1;//如果发现子树不平衡之后就没有必要进行下面的高度的求解了
        //left,right初始化都是0
        if (Math.abs(left-right)>1) return -1;
        else{
            return 1+(left>right ?left:right);
        }
    }
    public boolean IsBalanced_Solution(TreeNode root){
        return depth(root) !=-1;
    }
}
///二
class Solution {
    public boolean isBalanced(TreeNode root) {
        if(root==null)
            return true;
        if(dfs(root)<0){
            return false;
        }else{
            return true;
        }

    }
    public int dfs(TreeNode root){
        if(root==null)
            return 0;
        int left=dfs(root.left);
        int right=dfs(root.right);
        if(left<-1||right<-1||Math.abs(left-right)>1){
            return -2;
        }
        return Math.max(left,right)+1;
    }
}
           

40、数组中只出现一次的数

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

用的map

package M36TO40;

import java.util.HashMap;

public class SoluFindNumsAppearOnce {
    public void FindNumsAppearOnce(int[] array,int num1[],int num2[]) {
        HashMap<Integer, Integer> map = new HashMap<>();
        for (int i = 0; i < array.length; i++) {
            if (map.containsKey(array[i])) {
                map.put(array[i], 2);
            } else {
                map.put(array[i], 1);
            }
        }
        int count = 0;
        for (int i=0;i<array.length;i++){
            if (map.get(array[i])==1){
                if (count==0){
                    num1[0] = array[i];
                    count++;
                }else{
                    num2[0] = array[i];
                }
            }
        }
    }
}

           

用亦或的:

class Solution {
    public int[] singleNumbers(int[] nums) {
        //假设a b只出现一次
        //先求出 a^b
        int mid=nums[0];
        for(int i=1;i<nums.length;i++){
            mid ^=nums[i];
        }
        //a^b 找到值的最后一个1
        //则 a b两个值的二进制在这一个位置是一定一个是0一个是1
        mid -= mid&(mid-1);
        int[] res = new int[2];
        for(int i=0;i<nums.length;i++){
            //数组可以分为两组[a x1 x2 x3...] [b x4 x5 x6...]
            //一组中对应二进制为1的位置上的数为0 一组为1,然后组内进行异或运算,这最后分别剩下 a b
            if((mid&nums[i])==0){
                res[0] ^=nums[i];
            }else{
                res[1] ^=nums[i];
            }
        }
        if (res[0] > res[1]) {
            int temp = res[0];
            res[0] = res[1];
            res[1] = temp;
        }
        return res;
    }
}
           

继续阅读