LeetCode993. 二叉树的堂兄弟节点 / 剑指 Offer 44. 数字序列中某一位的数字 / 剑指 Offer 45. 把数组排成最小的数

Posted Zephyr丶J

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LeetCode993. 二叉树的堂兄弟节点 / 剑指 Offer 44. 数字序列中某一位的数字 / 剑指 Offer 45. 把数组排成最小的数相关的知识,希望对你有一定的参考价值。

993. 二叉树的堂兄弟节点

2021.5.17 每日一题

题目描述

在二叉树中,根节点位于深度 0 处,每个深度为 k 的节点的子节点位于深度 k+1 处。

如果二叉树的两个节点深度相同,但 父节点不同 ,则它们是一对堂兄弟节点。

我们给出了具有唯一值的二叉树的根节点 root ,以及树中两个不同节点的值 x 和 y 。

只有与值 x 和 y 对应的节点是堂兄弟节点时,才返回 true 。否则,返回 false。

示例 1:
在这里插入图片描述
输入:root = [1,2,3,4], x = 4, y = 3
输出:false

示例 2:
在这里插入图片描述
输入:root = [1,2,3,null,4,null,5], x = 5, y = 4
输出:true

示例 3:
在这里插入图片描述
输入:root = [1,2,3,null,4], x = 2, y = 3
输出:false

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/cousins-in-binary-tree
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

根据值找结点,记录父节点,深度

深度优先搜索
class Solution {
    //七个月前写的,有点久远了,先写深搜
    //记录两个结点的深度和值

    int x;
    int y;
    TreeNode xparent;
    TreeNode yparent;
    int xdeep;
    int ydeep;
    boolean xfound;
    boolean yfound;

    public boolean isCousins(TreeNode root, int x, int y) {
        this.x = x;
        this.y = y;

        dfs(root, 0, null);

        return xparent != yparent && xdeep == ydeep; 
    }

    public void dfs(TreeNode root, int deep, TreeNode parent){
        if(root == null)
            return;
        if(root.val == x){
            xdeep = deep;
            xparent = parent;
            xfound = true;
        }

        if(root.val == y){
            ydeep = deep;
            yparent = parent;
            yfound = true;
        }

        if(xfound && yfound)
            return;
        
        dfs(root.left, deep + 1, root);

        dfs(root.right, deep + 1, root);
    }

}
广度优先

本来想着能更简单点的,没想到也没多简单…还不如一个个记录信息了

class Solution {
    //广度优先搜索,相比于深搜,广度可以确保在同一层上,因此不用记录深度
    //还是得记录父节点,要不然写的太麻烦了,需要很多判断
    class Node{
        TreeNode node;
        TreeNode parent;

        public Node(TreeNode node, TreeNode parent){
            this.node = node;
            this.parent = parent;
        }
    }


    public boolean isCousins(TreeNode root, int x, int y) {
        boolean found = false;
        TreeNode p = null;

        Queue<Node> queue = new LinkedList<>();

        queue.offer(new Node(root, null));

        while(!queue.isEmpty()){
            int size = queue.size();
            //同一层
            while(size > 0){
                TreeNode node = queue.peek().node;
                TreeNode parent = queue.poll().parent;
                //当该层出现了一个,再出现另一个,且父节点不相同时,返回true
                if(found == true && (node.val == x || node.val == y) && parent != p)
                    return true;
                //出现一个,标记found,记录父节点
                if(node.val == x || node.val == y){
                    found = true;
                    p = parent; 
                }
                if(node.left != null){
                    queue.offer(new Node(node.left, node));
                }

                if(node.right != null){
                    queue.offer(new Node(node.right, node));
                }
                size--;
            }
            //该层只出现了一个,返回false
            if(found == true)
                return false;
        }

        return false; 
    }
}

剑指 Offer 44. 数字序列中某一位的数字

题目描述

数字以0123456789101112131415…的格式序列化到一个字符序列中。在这个序列中,第5位(从下标0开始计数)是5,第13位是1,第19位是4,等等。

请写一个函数,求任意第n位对应的数字。

示例 1:

输入:n = 3
输出:3

示例 2:

输入:n = 11
输出:0

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/shu-zi-xu-lie-zhong-mou-yi-wei-de-shu-zi-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

和上一道剑指offer一样,找规律题,这个相对比较简单,但难的依然是细节…
一位数0-9,一共10个
两位数10 - 99 ,一共90个
三位数100 - 999,一共900个
根据这个规律,确定当前数字的位数,然后再找到当前数字和所取下标

然后注意当 n 比较大时,会超出int的范围,需要用long
终于再改了好几次后,过了,不容易,细节是魔鬼

class Solution {
    public int findNthDigit(int n) {
        //一位数10个,下标0 - 9
        //两位数10-99,90个,下标,10 - 189
        //三位数,100 - 999,900个, 下标 190 - 2889
        //规律还是挺好找的
        int base = 1;   //刚开始一位数
        long count = 1 * 9;		//注意用long
        //计算是几位数
        while(count * base < n){
            n -= count * base;
            count *= 10;
            base++;
        }

        //到这里,base 为当前是几位数,n为下标,因为从0开始,所以要减1
        int x = (n - 1) / base ;       //当前位数的第几个数
        int y = (n - 1) % base;       //取这个数的第几个下标

        long digit = (long)(Math.pow(10, base - 1));
        long num = digit + x;		//当前数字
        int res = 0;				//结果
        //从左到右取
        for(int i = 0; i <= y; i++){	
            res = (int)(num / digit);	//取最高位
            num = num - res * digit;
            digit /= 10;
        }
        return res;
    }
}

剑指 Offer 45. 把数组排成最小的数

题目描述

输入一个非负整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。

 
示例 1:

输入: [10,2]
输出: "102"

示例 2:

输入: [3,30,34,5,9]
输出: "3033459"

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/ba-shu-zu-pai-cheng-zui-xiao-de-shu-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

之前每日一题出过 179. 最大数
这个题和那个题基本一样,一个是求最大,一个求最小
所以还是排序问题,主要是排序规则怎么制定?

这次看到题的第一反应,对于两个数的比较,如果位数相同,就逐位比较,小的在前,大的在后
如果位数不同,那么将位数少的数字循环,例如34和3435比较,就是3434和3435比较,然后依据位数相同的比较规则进行排序

然后又瞟了一下以前做的,是拼接后排序,将数字转换成字符串,对于a、b两个字符串,如果a + b < b + a,那么a排在b前面,反之b在a前面,更加直观
最后结果不需要去前导0

class Solution {
    public String minNumber(int[] nums) {
        //做完每日一题来看这个题,就是转成字符串拼接呗
        int l = nums.length;
        String[] temp = new String[l];
        for(int i = 0; i < l; i++){
            temp[i] = String.valueOf(nums[i]);
        }

        Arrays.sort(temp, (a,b)->{
            return (a+b).compareTo(b+a);
        });

        StringBuffer sb = new StringBuffer();
        for(String s : temp){
            sb.append(s);
        }
        return sb.toString();
    }
}
运用快排排序

再记快排,注意先处理右边的逻辑,并且取等号,这样结果才是正确的

class Solution {
    //再学习一下快排的写法,好好学习下
    public String minNumber(int[] nums) {
        String[] strs = new String[nums.length];
        for(int i = 0; i < nums.length; i++)
            strs[i] = String.valueOf(nums[i]);
        quickSort(strs, 0, strs.length - 1);
        StringBuilder res = new StringBuilder();
        for(String s : strs)
            res.append(s);
        return res.toString();
    }
    void quickSort(String[] strs, int l, int r) {
        //如果l比r大了,那说明整理好了
        if(l >= r) return;
        int i = l, j = r;
        String tmp = strs[i];
        //基准是最左边的位置
        while(i < j) {
            //如果右边的数拼接最左边的数大于等于左边的数拼接右边的数,就说明右边的数大,那么就应该自减,继续判断,好好捋一捋这个逻辑
            while((strs[j] + strs[l]).compareTo(strs[l] + strs[j]) >= 0 && i < j) j--;
            //这里同理,左边是小的数,所以左加右要小于右加左才自加
            while((strs[i] + strs[l]).compareTo(strs[l] + strs[i]) <= 0 && i < j) i++;
            //遇到不满足条件的两个位置的数就进行交换
            tmp = strs[i];
            strs[i] = strs[j];
            strs[j] = tmp;
        }
        //然后把最左边的数放到中间
        strs[i] = strs[l];
        strs[l] = tmp;
        //再对分开的两个数组进行排序
        quickSort(strs, l, i - 1);
        quickSort(strs, i + 1, r);
    }
}

以上是关于LeetCode993. 二叉树的堂兄弟节点 / 剑指 Offer 44. 数字序列中某一位的数字 / 剑指 Offer 45. 把数组排成最小的数的主要内容,如果未能解决你的问题,请参考以下文章

⭐算法入门⭐《二叉树》简单07 —— LeetCode 993. 二叉树的堂兄弟节点

追求最优美的代码 leetcode 993. 二叉树的堂兄弟节点

追求最优美的代码 leetcode 993. 二叉树的堂兄弟节点

LeetCode 993. 二叉树的堂兄弟节点

[LeetCode]993. 二叉树的堂兄弟节点(Java/c++ DFS)

[LeetCode]993. 二叉树的堂兄弟节点(Java/c++ DFS)