编写递归函数、回溯函数的返回值类型确定

在力扣上遇到这么一道题目,本身倒是不难,DFS一遍就解决了,却引发了我对递归函数返回值类型定义的思考。

题目描述和问题介绍

题目和类定义如下图所示:

// Definition for a Node.
class Node {
public:
    int val;
    Node* left;
    Node* right;

    Node() {}

    Node(int _val) {
        val = _val;
        left = NULL;
        right = NULL;
    }

    Node(int _val, Node* _left, Node* _right) {
        val = _val;
        left = _left;
        right = _right;
    }
};

我的思考

从直观感受来说,题目要求输出第k大的值,那么定义一个dfs函数,这个函数的返回值应该是int类型比较好吧?

然而看看题解,高赞题解的普遍写法是把dfs函数定义成void,要么是定义一个全局变量用来储存结果,如下图所示

class Solution {
public: 
    int res;
    int kthLargest(TreeNode* root, int k) {
        dfs(root,k);
        return res;
    }
    void dfs(TreeNode* root ,int &k) //传引用 这里需要保证所有dfs函数共用一个k 
    {
        if(!root) return;
        dfs(root->right,k); //右
        k--;
        if(!k) res = root->val; //根
        dfs(root->left,k); //左
    }
};

或者是这样,把结果放在参数列表里随着递归修改,记得参数类型要引用。

class Solution {
public: 
    int kthLargest(TreeNode* root, int k) {
        dfs(root,k);
        return res;
    }
    void dfs(TreeNode* root ,int &k,int& res) //传引用 这里需要保证所有dfs函数共用一个k 
    {
        if(!root) return;
        dfs(root->right,k); //右
        k--;
        if(!k) res = root->val; //根
        dfs(root->left,k); //左
    }
};

那么可不可以把返回值定义为int呢?也行,不过理解起来就比较抽象了,因为每调用一次递归就会产生一个返回值,也就是说一棵树执行下来要返回好多个int值,这些值哪些是表示答案的呢?哪些值是可以丢掉的呢?或者说答案是这些返回值的和或者运算结果呢?这些都是要考虑的问题,对于本题来说,至多有一个int值是题目答案,其他返回值都应该无视。修改后的代码如下图所示:

class Solution {
public: 
    int kthLargest(TreeNode* root, int k) {
        return dfs(root, k);
    }

    int dfs(TreeNode* root, int& k) {
        if (!root) return -1; // Return -1 to indicate no valid kth element found.
        
        int rightResult = dfs(root->right, k); // Explore right subtree
        
        // If kth element is found in the right subtree, return it.
        if (k == 0) return rightResult;
        
        k--; // Decrement k since we are now visiting the current node.
        
        // If kth element is found in the current node, return it.
        if (k == 0) return root->val;
        
        return dfs(root->left, k); // Explore left subtree if kth element is not found yet.
    }
};

这段代码的解释是,遍历右中左子树,当遍历到第k个值时return答案,否则继续遍历,return dfs(root -> left, k),直到能找到合适的返回值。这么一看流程不是很清晰,但是运行结果确实是一样的。

总结

递归函数的返回值是否应该使用void取决于函数的具体需求和实现方式。在很多情况下,递归函数并不需要返回值,因为它们的目的是通过递归调用来解决问题,而不是返回特定的结果。在这种情况下,使用void作为返回值类型是合适的。

使用void返回值的递归函数的一个优点是简洁性,因为不需要处理返回值,减少了代码的复杂性和潜在的错误,可以把答案放在private变量,或者递归函数的参数中,这样代码的可读性比较高,后续也方便修改和调试。

在二叉搜索树中查找第k大元素,需要找到并返回第k大的元素值。在这种情况下,我们可能会使用类似int的返回值类型。如上所示,int 返回值是可以达到效果的。

要确定适合的返回值类型,可以考虑以下几个因素:

  1. 问题的性质:根据问题的性质,确定是否需要返回特定的结果。有些问题需要从递归中获取结果,而有些问题则不需要。

  2. 函数的目的:确定递归函数的主要目标是什么。如果主要目标是解决问题,并不需要返回特定的结果,那么void返回值是合适的。

  3. 代码的复杂性:有时,在递归函数中处理返回值可能会增加代码的复杂性。如果可以避免使用返回值,可以使代码更简洁易读。

  4. 全局变量或引用参数:在一些情况下,可以使用全局变量或引用参数来获取递归函数的结果,而不使用返回值。

推荐我这种新手还是不要整花里胡哨的,老老实实把流程和逻辑写的清清楚楚,搞错了还好debug,直观才是最重要的。

猜你喜欢

转载自blog.csdn.net/weixin_43694670/article/details/132009282