leetcode

Posted 旧时星空

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了leetcode相关的知识,希望对你有一定的参考价值。

leetcode(2)

根据二叉树创建字符串–简单

递归

class Solution:
    def tree2str(self, root: Optional[TreeNode]) -> str:
        if root is None:
            return ""
        if root.left is None and root.right is None:
            return str(root.val)
        if root.right is None:
            return f"root.val(self.tree2str(root.left))"
        return f"root.val(self.tree2str(root.left))(self.tree2str(root.right))"

迭代

我们也可以使用迭代的方法得到二叉树的前序遍历,并在迭代时加上额外的括号。

用一个栈来存储树中的一些节点,其中栈顶的元素为当前遍历到的节点,从栈底到栈顶的节点为从根到当前节点的唯一路径上的节点。和迭代得到前序遍历的方法略有不同,由于这里需要输出额外的括号,因此我们还需要用一个集合存储所有遍历过的节点,理由见下文。

首先我们把根节点入栈。对于当前栈顶的元素,如果它没有遍历过,那么就把它加入到集合中,并开始对以它为根的子树进行前序遍历。我们先在答案末尾添加一个 \\text`(’‘(’,表示一个节点的开始,然后判断该节点的子节点个数。

和方法一相同,这里会出现四种情况:

如果当前节点有两个孩子,那么我们先将右孩子入栈,再将左孩子入栈,从而保证前序遍历的顺序;
如果当前节点没有孩子,我们什么都不做;
如果当前节点只有左孩子,那么我们将左孩子入栈;
如果当前节点只有右孩子,那么需要在答案末尾添加一对 \\text()'‘()’ 表示空的左孩子,再将右孩子入栈。 注意这四种情况中,我们都不会将当前节点出栈,原因是我们一开始添加了 \\text(’‘(’ 表示节点的开始,在以当前节点为根的子树中所有节点遍历完成之后,我们才会在答案末尾添加 \\text)'‘)’ 表示节点的结束。因此我们需要用上面提到的集合来存储遍历过的节点,如果当前栈顶的元素遍历过,那么就需要在答案末尾添加 \\text)’‘)’ ,并将这个节点出栈。

class Solution:
    def tree2str(self, root: Optional[TreeNode]) -> str:
        ans = ""
        st = [root]
        vis = set()
        while st:
            node = st[-1]
            if node in vis:
                if node != root:
                    ans += ")"
                st.pop()
            else:
                vis.add(node)
                if node != root:
                    ans += "("
                ans += str(node.val)
                if node.left is None and node.right:
                    ans += "()"
                if node.right:
                    st.append(node.right)
                if node.left:
                    st.append(node.left)
        return ans

具有所有最深节点的最小子树–中等

深度优先搜索

最直白的做法,先做一次深度优先搜索标记所有节点的深度来找到最深的节点,再做一次深度优先搜索用回溯法找最小子树。定义第二次深度优先搜索方法为 answer(node),每次递归有以下四种情况需要处理:

如果 node 没有左右子树,返回 node。

如果 node 左右子树的后代中都有最深节点,返回 node。

如果只有左子树或右子树中有且拥有所有的最深节点,返回这棵子树的根节点(即 node 的左/右孩子)。

否则,当前子树中不存在答案。

算法

先做一次深度优先搜索标记所有节点的深度,再做一次深度优先搜索找到最终答案。

class Solution(object):
    def subtreeWithAllDeepest(self, root):
        # Tag each node with it's depth.
        depth = None: -1
        def dfs(node, parent = None):
            if node:
                depth[node] = depth[parent] + 1
                dfs(node.left, node)
                dfs(node.right, node)
        dfs(root)

        max_depth = max(depth.itervalues())

        def answer(node):
            # Return the answer for the subtree at node.
            if not node or depth.get(node, None) == max_depth:
                return node
            L, R = answer(node.left), answer(node.right)
            return node if L and R else L or R

        return answer(root)

作者:LeetCode
链接:https://leetcode-cn.com/problems/smallest-subtree-with-all-the-deepest-nodes/solution/ju-you-suo-you-zui-shen-jie-dian-de-zui-xiao-zi-sh/

下一个更大元素–中等

线性解法

这种方法中,我们同样将给定数字 nn 当做字符串数组 aa,首先我们观察到任意降序的序列,不会有更大的排列出现。

比方说,下面数列就没有下一排列:

[9, 5, 4, 3, 1]
我们需要从右往左找到第一对连续的数字 a[i]a[i] 和 a[i-1]a[i−1] 满足 a[i-1] < a[i]a[i−1]<a[i]。到当前位置位置位置,a[i-1]a[i−1] 右边的数字没办法产生一个更大的排列,因为右边的数字是降序的。所以我们需要重新排布 a[i-1]a[i−1] 到最右边的数字来得到下一个排列。

那么怎样排布能得到下一个更大的数字呢?我们想得到恰好大于当前数字的下一个排列,所以我们需要用恰好大于 a[i-1]a[i−1] 的数字去替换掉 a[i-1]a[i−1],比方说我们让这个数字为 a[j]a[j]。

我们将 a[i-1]a[i−1] 和 a[j]a[j] 交换,我们现在在下标为 i-1i−1 的地方得到了正确的数字,但当前的结果还不是一个正确的排列。我们需要用从 i-1i−1 开始到最右边数字剩下来的数字升序排列,来得到它们中的最小排列。

我们注意到在从右往左找到第一对 a[i-1] < a[i]a[i−1]<a[i] 的连续数字前, a[i-1]a[i−1] 右边的数字都是降序排列的,所以交换 a[i-1]a[i−1] 和 a[j]a[j] 不会改变下标从 ii 开始到最后的顺序。所以我们在交换了 a[i-1]a[i−1] 和 a[j]a[j] 以后,只需要反转下标从 ii 开始到最后的数字,就可以得到下一个字典序最小的排列。

class Solution 
public:
    int nextGreaterElement(int n) 
        string s = to_string(n);
        int len = s.size();
        int ptr = len - 2, revPtr = len - 1, ans = 0;
        long long mul = 1, judge = 0;
        //找ptr的位置
        while(ptr >= 0)
            if(s[ptr] - '0' < s[ptr + 1] - '0') break;
            ptr--;
        
        if(ptr < 0) return -1;
        //确定revPtr的位置
        while(revPtr > ptr)   //这一步是在给它找初值,这个初值不是随便找的,必须也得是大于ptr元素
            if(s[revPtr] - '0' > s[ptr] - '0') break;
            revPtr--;
        
        for(int i = len - 1; i > ptr; i--)
            if(s[i]-'0' > s[ptr]-'0' && s[revPtr]-'0' > s[i]-'0') revPtr = i;
        
        //调换两个的位置
        char ch = s[ptr];
        s[ptr] = s[revPtr];
        s[revPtr] = ch;

        //ptr右部分进行排序
        sort(s.begin() + ptr + 1, s.end());
        //string → int
        for(int i = len - 1; i >= 0; i--)
            judge += (s[i] - '0') * mul;   //为了不溢出,先用一个long long型的数判断一下,有没有溢出
            if(judge <= INT_MAX)
                ans += (s[i] - '0') * mul;
                mul *= 10;
            
            else return -1;
        
        return ans;
    
;

递增顺序查找树–中等

事实上,还可以遍历一次输入二叉搜索树,在遍历的过程中改变节点指向以满足题目的要求。

在中序遍历的时候,修改节点指向就可以实现。具体地,当我们遍历到一个节点时,把它的左孩子设为空,并将其本身作为上一个遍历到的节点的右孩子。这里需要有一些想象能力。递归遍历的过程中,由于递归函数的调用栈保存了节点的引用,因此上述操作可以实现。

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution(object):
    def increasingBST(self, root):
        dummy = TreeNode(-1)
        self.prev = dummy
        self.inOrder(root)
        return dummy.right
        
    def inOrder(self, root):
        if not root:
            return None
        self.inOrder(root.left)
        root.left = None
        self.prev.right = root
        self.prev = root
        self.inOrder(root.right)

重新排列数组–简单

class Solution 
    public int[] shuffle(int[] nums, int n) 
        int len = nums.length;
        int[] ans = new int[len];
        int index = 0;
        for(int i = 0;i < len - n;i++)
            ans[index++] = nums[i];
            ans[index++] = nums[i+n]; 
        
        return ans;
    

以上是关于leetcode的主要内容,如果未能解决你的问题,请参考以下文章

Leetcode 652.寻找重复的子树

LeetCode 572. 另一个树的子树

LeetCode Algorithm 572. 另一棵树的子树

[LeetCode] Count Univalue Subtrees 计数相同值子树的个数

LeetCode 450 删除二叉搜索树中的节点[dfs] HERODING的LeetCode之路

[LeetCode] 226. Invert Binary Tree JAVA