简体   繁体   English

查找单链列表的第k个元素

[英]Finding the kth to last element of a singly linked list

I have two recursive solutions to the "kth to last element of a singly linked list" problem in Java: 对于Java中的“单链列表的第k个元素”,我有两种递归解决方案:

Solution 1: 解决方案1:

public static Node nthToLast(Node head, int k , int i){
    if (head == null) return null;
    Node n = nthToLast(head.next, k, i);
    i = i + 1;

    if (i == k) return head;

    return n;
}

Solution 2: 解决方案2:

public class IntWrapper {
    public int value = 0;
}
public static Node nthToLast(Node head, int k, IntWrapper i){
    if (head == null) return null;
    Node n = nthToLast(head.next, k, i);
    i.value = i.value + 1;

    if (i.value == k) return head;

    return n;
}

The first solution returns null , while the second solution works perfectly. 第一个解决方案返回null ,而第二个解决方案完美运行。 The first solution passes k by value, while the second solution wraps the int value in a class and passes it. 第一个解决方案按值传递k ,而第二个解决方案将int值包装在一个类中并传递它。

I have two questions: 我有两个问题:

  1. Why is the first solution not working in Java? 为什么第一个解决方案在Java中不起作用? Why is pass-by-value through the local variable i in each method call not working the same as the pass-by-reference version? 为什么在每个方法调用中通过局部变量i的值传递与传递引用版本不同?

  2. The Integer class in Java wraps int , but replacing the int to Integer in the first solution does not work as well. Java中的Integer类包装了int ,但是在第一个解决方案中将int替换为Integer并不能正常工作。 Why? 为什么?

1. The first solution does not work because every time you pass the same value in a i variable. 1.第一种解决方案不起作用,因为每次您在i变量中传递相同的值。 If you move the line i = i + ​​1 over the line Node n = nthToLast (head.next, k, i) , everything should work without a problem. 如果将行i = i + ​​1移到行Node n = nthToLast (head.next, k, i) ,则一切都应该正常工作。
2. Integer class is immutable, so behaves like a normal int . 2. Integer类是不可变的,因此其行为类似于普通的int That's why if you use an Integer in the first solution function will not work correctly. 这就是为什么如果在第一个解决方案中使用Integer函数将无法正常工作的原因。 You can replace lines of code as I mentioned above that the first solution worked with an Integer . 您可以替换上面我提到的第一个解决方案与Integer一起使用的代码行。
The second solution works because the way you increment the counter does not overwrite the reference to the counting object. 第二种解决方案之所以有效,是因为您增加计数器的方式不会覆盖对计数对象的引用。

In Solution 2, you're using IntWrapper to remember values across recursive invocations. 在解决方案2中,您正在使用IntWrapper记住跨递归调用的值。 Here, IntWrapper acts like a global value. 在这里, IntWrapper作用就像一个全局值。

If you use local variables such as a primitive integer, you cannot preserve the incremented ( i = i + 1 ) values across invocations. 如果使用局部变量(例如原始整数),则无法在调用之间保留递增的( i = i + 1 )值。 Therefore, the statement if (i == k) return head; 因此,语句if (i == k) return head; never becomes true, unless maybe if k = 1. 除非k = 1。

Most interestingly, you cannot use Integer because Java wrapper classes are immutable in nature. 最有趣的是,您不能使用Integer因为Java包装器类本质上是不可变的。 The moment you do i = i + 1 , a new object is created (LHS) and the old one (RHS) is thrown away/garbage collected. 当您执行i = i + 1的那一刻,将创建一个新对象(LHS),而一个旧对象(RHS)将被丢弃/收集垃圾。

In your solution 1 you should increment i before calling recursively the method. 在您的解决方案1中,您应在递归调用该方法之前使i递增。 This version should work: 这个版本应该工作:

public static Node nthToLast(Node head, int k , int i) {
    // checks empty case
    if (head == null) { return null; }

     // checks if current node is the solution
    if (i == k) { return head; }

    // else checks next node
    return nthToLast(head.next, k, i+1); 
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM