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. 二叉树的堂兄弟节点