【问题标题】:Is it possible to implement an algorithm to find the nth to last element of a singly linked list using recursion in java是否可以使用java中的递归实现一种算法来查找单链表的倒数第n个元素
【发布时间】:2013-04-21 22:10:58
【问题描述】:

我知道你可以简单地迭代地解决这个问题,方法是每次在链表中传递一个节点时使用一个计数器递增;还创建一个数组列表并设置其中每个节点找到的数据。一旦你碰到了链表的尾部,只需从数组列表中的元素总数中减去第 N 项,你就可以返回答案。但是,有人将如何使用递归来执行此操作?是否可能,如果可以,请显示代码以显示您的天才:)。

注意:我知道您不能在 Java 中返回两个值(但在 C/C++ 中,您可以使用指针:])

编辑:这是我在网上找到的一个简单问题,但我添加了递归部分以使其成为我自己的挑战,我发现使用 Java 可能是不可能的。

【问题讨论】:

  • 你付出了多少努力?
  • 好吧,正如您已经知道的,在递归中,您需要返回尾指针,这样就要求您的整个函数具有 ListNode 的返回类型,但是有人将如何返回节点本身的数据?顺便说一句,这是一本面试书中的问题。

标签: java recursion linked-list


【解决方案1】:

递归函数:

int n_to_end(Node *no, int n, Node **res)
{
    if(no->next == NULL)
    {
            if(n==0)
                    *res = no;
            return 0;
    }
    else
    {
            int tmp = 1 + n_to_end(no->next, n, res);
            if(tmp == n)
                    *res = no;
            return tmp;
    }
}

包装函数:

Node *n_end(Node *no, int n)
{
    Node *res;
    res = NULL;
    int m = n_to_end(no, n, &res);
    if(m < n)
    {
            printf("max possible n should be smaller than or equal to: %d\n", m);
    }
    return res;
}

调用函数:

int main()
{
    List list;
    list.append(3);
    list.append(5);
    list.append(2);
    list.append(2);
    list.append(1);
    list.append(1);
    list.append(2);
    list.append(2);

    Node * nth = n_end(list.head, 6);
    if(nth!=NULL)
    printf("value is: %d\n", nth->val);
}

此代码已使用不同的输入进行了测试。虽然是 C++ 版本,但你应该能弄清楚其中的逻辑 :)

【讨论】:

    【解决方案2】:

    作为一般规则,可以用循环完成的任何事情也可以用任何合理的语言通过递归完成。解决方案的优雅可能大相径庭。这是一个相当 java 惯用的版本。为简洁起见,我省略了常用的访问器函数。

    这里的想法是递归到列表的末尾并在递归展开时增加一个计数器。当计数器达到期望值时,返回该节点。否则返回null。非空值一直返回到顶部。一次在列表中,一次在列表中。最小的争论。没有不尊重亚当的意思,但我认为这更简单。

    注意:OP 关于 Java 只能返回一个值的说法是正确的,但是由于该值可以是任何对象,因此您可以根据自己的选择返回带有字段或数组元素的对象。但是,这里不需要。

    public class Test {
    
        public void run() {
            Node node = null;
    
            // Build a list of 10 nodes.  The last is #1
            for (int i = 1; i <= 10; i++) {
                node = new Node(i, node);
            }
    
            // Print from 1st last to 10th last.
            for (int i = 1; i <= 10; i++) {
                System.out.println(i + "th last node=" + node.nThFromLast(i).data);
            }
        }
    
        public static void main(String[] args) {
            new Test().run();
        }
    }
    
    class Node {
        int data;   // Node data
        Node next;  // Next node or null if this is last
    
        Node(int data, Node next) {
            this.data = data;
            this.next = next;
        }
    
        // A context for finding nth last list element. 
        private static class NthLastFinder {
            int n, fromLast = 1;
    
            NthLastFinder(int n) {
                this.n = n;
            }
    
            Node find(Node node) {
                if (node.next != null) { 
                    Node rtn = find(node.next);
                    if (rtn != null) {
                        return rtn;
                    }
                    fromLast++;
                }
                return fromLast == n ? node : null;
            }
        }
    
        Node nThFromLast(int n) {
            return new NthLastFinder(n).find(this);
        }
    }
    

    【讨论】:

    • 感谢整个代码。非常详细!感谢您对此的解释:)。
    【解决方案3】:

    诀窍是在递归之后完成工作。私有方法中的数组基本上是作为对可变整数的引用。

    class Node {
      Node next;
      int data;
    
      public Node findNthFromLast(int n) {
        return findNthFromLast(new int[] {n});
      }
    
      private Node findNthFromLast(int[] r) {
        Node result = next == null ? null : next.findNthFromLast(r);
        return r[0]-- == 0 ? this : result;  
      }
    }
    

    【讨论】:

    • 我真的很喜欢这个答案。很短但很强大。
    【解决方案4】:

    好的,我认为这应该可以解决问题。这是在C++,但它应该很容易转换为Java。我也没有测试过。

    Node *NToLastHelper(Node *behind, Node *current, int n) {
      // If n is not yet 0, keep advancing the current node
      // to get it n "ahead" of behind.
      if (n != 0) {
        return NToLastHelper(behind, current->next, n - 1);
      }
      // Since we now know current is n ahead of behind, if it is null
      // the behind must be n from the end.
      if (current->next == nullptr) {
        return behind;
      }
      // Otherwise we need to keep going.
      return NToLastHelper(behind->next, current->next, n);
    }
    
    Node *NToLast(Node *node, int n) {
      // Call the helper function from the head node.
      return NToLastHelper(node, node, n);
    }
    

    edit:如果要返回最后一个节点的值,只需将其更改为:

    int NToLast(Node *node, int n) {
      // Call the helper function from the head node.
      return NToLastHelper(node, node, n)->val;
    }
    

    如果节点为空,此代码将严重失败。

    【讨论】:

    • 感谢您的尝试。顺便说一句,为什么我的问题得到负面评价。这是个坏问题吗?
    • @MingoVanBurne 感谢您的尝试是什么意思?这不是您正在寻找的解决方案吗?
    • @MingoVanBurne 你的问题被否决了,因为人们认为它没有表现出足够的努力或研究。下次,您可以尝试在寻求帮助的同时提供您的尝试。
    • 感谢您的回答。我的问题是将第 N 个节点的值返回到最后,这意味着如果 N 为 2,则返回该 LinkedList 的第 2 个到最后一个节点值。
    • @MingoVanBurne 就是这样做的。
    猜你喜欢
    • 1970-01-01
    • 2013-12-10
    • 1970-01-01
    • 1970-01-01
    • 2013-09-20
    • 2021-12-21
    • 2011-01-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多