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. 序列化二叉树的主要内容,如果未能解决你的问题,请参考以下文章

leetcode1734. 解码异或后的排列

leetcode1734. 解码异或后的排列

我用java刷 leetcode 1734. 解码异或后的排列

LeetCode 1734 解码异或后的排列[数学] HERODING的LeetCode之路

LeetCode1734. 解码异或后的排列 / 剑指 Offer 36. 二叉搜索树与双向链表 / 剑指 Offer 37. 序列化二叉树

1734. 解码异或后的排列(思维)