LeetCode1734. 解码异或后的排列 / 剑指 Offer 36. 二叉搜索树与双向链表 / 剑指 Offer 37. 序列化二叉树
Posted Zephyr丶J
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LeetCode1734. 解码异或后的排列 / 剑指 Offer 36. 二叉搜索树与双向链表 / 剑指 Offer 37. 序列化二叉树相关的知识,希望对你有一定的参考价值。
LeetCode1734. 解码异或后的排列
2021.5.11 每日一题
题目描述
给你一个整数数组 perm ,它是前 n 个正整数的排列,且 n 是个 奇数 。
它被加密成另一个长度为 n - 1 的整数数组 encoded ,满足 encoded[i] = perm[i] XOR perm[i + 1] 。比方说,如果 perm = [1,3,2] ,那么 encoded = [2,1] 。
给你 encoded 数组,请你返回原始数组 perm 。题目保证答案存在且唯一。
示例 1:
输入:encoded = [3,1]
输出:[1,2,3]
解释:如果 perm = [1,2,3] ,那么 encoded = [1 XOR 2,2 XOR 3] = [3,1]
示例 2:
输入:encoded = [6,5,4,6]
输出:[2,4,1,5,3]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/decode-xored-permutation
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
最近一段时间每日一题出了几道异或的题,然后自己想了半天还是没想出来,怎么说呢,感觉思维变的越来越僵硬了…
要注意到题目中关键点,前n个正整数,而前几天有道题,我们就是根据4k,4的倍数的规律求得前n个正整数的异或值,这是第一点
然后再想到关键问题就是要求出原数组perm中的一个数,例如第一个数;
而想到两个相同的数异或为0;而1到n的异或已经求出来了,那么,只要知道n - 1 个数的异或值,那么第n个数就能求了
再看所给的数组,encoded[1] = prem[1] ^ perm[2];encoded[3] = prem[3] ^ perm[4]…
n是奇数,那么将encoded[1] ^ encoded[3]…求出来,也就是n - 1 个数的异或值
再用n个数的异或结果与这个结果异或,就得到了perm[0]
主要是发现关键点!!!!
class Solution {
public int[] decode(int[] encoded) {
//和那天那个题相似,反过来了,但是感觉难度大了很多,就相当于解方程,两个方程三个未知数,确实不知道咋办
//n是正整数,意味着不等于0,试着用第一个举了个例子,把3,也就是11,拆分成10 01,然后去匹配第二个数01,
//01 01 不行,为0了,只能是10 01 也就是3
//再看看第二个例子,6,110拆成100 10,第二个5,101,如果2在第二位,那么101 ^ 10 等于111,然后继续异或10-->011-->101
//最后4 2 7 3 5 哈? 不唯一了,哦,漏看了一个字,前n个正整数
//那再想想
//能不能用到前几天那个规律,4的倍数,k ^ k + 1 = 1,k ^ k + 1 ^ k + 2 = k + 3; k ^ k + 1 ^ k + 2 ^ k + 3 = 0
//还是想不出来,只能看提示了
//然后就发现还是自己太蠢,先求1到n的异或为x,然后因为n是奇数,所以求第二个到第n个的异或,也就是
//encoded[1]^encoded[3]^encoded[5].....
//然后x与上式异或,就得到了perm[0]......
int l = encoded.length;
int n = l + 1;
int x = 0; //整体异或后的结果
if(n % 4 == 1){
x = 1;
}else{
x = 0;
}
int y = 0;
int index = 1;
while(index < l){
y ^= encoded[index];
index += 2;
}
int[] perm = new int[n];
perm[0] = x ^ y;
for(int i = 1; i < n; i++){
perm[i] = perm[i - 1] ^ encoded[i - 1];
}
return perm;
}
}
剑指 Offer 36. 二叉搜索树与双向链表
题目描述
输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的循环双向链表。要求不能创建任何新的节点,只能调整树中节点指针的指向。
为了让您更好地理解问题,以下面的二叉搜索树为例:
我们希望将这个二叉搜索树转化为双向循环链表。链表中的每个节点都有一个前驱和后继指针。对于双向循环链表,第一个节点的前驱是最后一个节点,最后一个节点的后继是第一个节点。
下图展示了上面的二叉搜索树转化成的链表。“head” 表示指向链表中有最小元素的节点。
特别地,我们希望可以就地完成转换操作。当转化完成以后,树中节点的左指针需要指向前驱,树中节点的右指针需要指向后继。还需要返回链表中的第一个节点的指针。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/er-cha-sou-suo-shu-yu-shuang-xiang-lian-biao-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
给的这个图很有误导性,我本来是想着head 是一个新的结点,然后指向链表中最小元素的结点,但是题目又说不能新建任何结点,奇奇怪怪的,应该把head直接标在1那个位置,这样就好理解了
做起来其实不难,拿一个指针记录前驱,一个记录头节点就行了
class Solution {
Node head, pre;
public Node treeToDoublyList(Node root) {
//又是树来了,因为是排序的,二叉搜索树中序遍历的结果就是排序的,所以容易想到是中序
//再有,因为是双向链表,所以要记录前一个遍历到的结果
//另外,开头结尾结点记录一下,方便最后处理开头结尾的指针
if(root == null)
return null;
inorder(root);
//到这里,pre指向最后一个节点,head是头部前一个节点
pre.right = head;
head.left = pre;
return head;
}
public void inorder(Node root){
if(root == null)
return;
inorder(root.left);
//处理当前指针
if(pre != null)
pre.right = root;
//如果为空,那么就是第一个结点
else head = root;
root.left = pre;
pre = root;
inorder(root.right);
}
}
剑指 Offer 37. 序列化二叉树
题目描述
请实现两个函数,分别用来序列化和反序列化二叉树。
示例:
你可以将以下二叉树:
1
/ \\
2 3
/ \\
4 5
序列化为 "[1,2,3,null,null,4,5]"
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/xu-lie-hua-er-cha-shu-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
咋说呢,这题不算太难,但是也有难度,马马虎虎也算能做出来,根据提示把所用null结点都加上, 进行序列化,那么反序列化回来的树就是唯一的,序列化简单,就是一个层序遍历,然后把结点值转换成字符串存储起来
反序列化也得用队列存储当前结点,然后依次进行遍历,每个结点对应Strring数组中两个位置。重要的是细节
这里参考Krahets大佬题解写的代码,学!!!!!!!!
public class Codec {
//这个题的主要问题是把这棵树序列化成什么样,并且能保证能反序列化回来,看所给的提示,层序遍历就可以,但是要把null标识出来
//下午来了写一下,序列化应该简单,就是层序遍历到什么填什么
//反序列化怎么办呢,等等再看
//我想的是一个非空结点后面肯定接的两个结点,然后用一个标记记录遍历到的结点,另一个标记记录遍历到的非空结点,
//然后依次连接,试着写一下,发现问题,发现并不像想的那么简单,因为是树,指针的移动是个问题,
//也得用queue
// Encodes a tree to a single string.
public String serialize(TreeNode root) {
if(root == null)
return "[]";
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
StringBuffer sb = new StringBuffer("[");
while(!queue.isEmpty()){
TreeNode temp = queue.poll();
if(temp != null){
//如果不为空
sb.append(temp.val + ",");
queue.offer(temp.left);
queue.offer(temp.right);
}else{
//如果为空
sb.append("null,");
}
}
//最后逗号要删除,并加上]
sb.deleteCharAt(sb.length() - 1);
sb.append("]");
return sb.toString();
}
// Decodes your encoded data to tree.
public TreeNode deserialize(String data) {
if(data.equals("[]"))
return null;
//因为每一个节点的值可能是个多位数,所以需要先分开,另外注意开头结尾是[]
String[] s = data.substring(1, data.length() - 1).split(",");
TreeNode root = new TreeNode(Integer.parseInt(s[0]));
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
int index = 1;
while(!queue.isEmpty()){
TreeNode node = queue.poll();
if(!s[index].equals("null")){
TreeNode left = new TreeNode(Integer.parseInt(s[index]));
node.left = left;
queue.offer(left);
}
index++;
if(!s[index].equals("null")){
TreeNode right = new TreeNode(Integer.parseInt(s[index]));
node.right = right;
queue.offer(right);
}
index++;
}
return root;
}
}
为了巩固一下,再写了先序遍历的方法吧,顺便把同样的297题做了,还能把今天三道题的积分拿了,美滋滋 ^ ~ ^
序列化还是很简单,但是反序列化的递归真的又难到我了,刚开始我是想着也用数组的,然后发现递归出口不知道咋整了,
然后发现题解前序遍历递归过程中都是传入的一个集合,集合中没有元素了好像递归就自动停止了?这个又算是学到新的东西了吧
public class Codec {
// Encodes a tree to a single string.
public String serialize(TreeNode root) {
if(root == null)
return "null";
return root.val + "," + serialize(root.left) + "," + serialize(root.right);
}
// Decodes your encoded data to tree.
public TreeNode deserialize(String data) {
//反序列化应该也是递归
String[] s = data.split(",");
Queue<String> queue = new LinkedList<>(Arrays.asList(s));
return deserialize(queue);
}
public TreeNode deserialize(Queue<String> queue){
String val = queue.poll();
if("null".equals(val)){
return null;
}
TreeNode node = new TreeNode(Integer.parseInt(val));
node.left = deserialize(queue);
node.right = deserialize(queue);
return node;
}
}
以上是关于LeetCode1734. 解码异或后的排列 / 剑指 Offer 36. 二叉搜索树与双向链表 / 剑指 Offer 37. 序列化二叉树的主要内容,如果未能解决你的问题,请参考以下文章
我用java刷 leetcode 1734. 解码异或后的排列
LeetCode 1734 解码异或后的排列[数学] HERODING的LeetCode之路
LeetCode1734. 解码异或后的排列 / 剑指 Offer 36. 二叉搜索树与双向链表 / 剑指 Offer 37. 序列化二叉树