【问题标题】:How to find the second to last Char occurrence in a linked list recursively?如何递归地查找链表中倒数第二个 Char 出现?
【发布时间】:2020-02-22 05:33:44
【问题描述】:

作为家庭作业,我假设返回字母倒数第二次出现的位置——以了解要检查的字母作为 Char 类型参数传递。我正在搜索的是一个自编码的链表。它还必须以递归方式完成,我一直在努力完全理解。这是我到目前为止的工作。

注意:如果一个字母出现 0 次或 1 次,则返回 -1。

例如 ["ababcdefb"].positionOfSecondToLastOccurrence('b') == 3

static class Node {
        public Node (char item, Node next) { this.item = item; this.next = next; }
        public char item;
        public Node next;
    }

Node first;

public int positionOfSecondToLastOccurrence (char letter) {

        if (first == null)
            return -1;

        return positionOfSecondToLastOccurrenceHelper(letter, first, 0);
    }

private int positionOfSecondToLastOccurrenceHelper(char c, Node n, int pos) {

        if (n.next == null)
            return n.item;

        return pos += compare(n.item, positionHelper(c, n.next, pos));

    }

private int compare(char c, int p) {

        int result = 0;

        if (c == p)
            return result += 1;

        return 0;
    }

我明白为什么这不起作用;我返回 1 的结果,然后在返回上一个函数调用时将其与 n.item 进行比较,这永远不会是真的。我不知道如何使这项工作。任何指导都会很棒。

【问题讨论】:

    标签: java recursion singly-linked-list


    【解决方案1】:

    您使用的是单链表,这意味着您只能在一个方向上遍历它,即向前,即从第一个节点到最后一个节点。

    然后算法是从第一个节点到最后一个节点遍历列表,并将每个节点的item 与您正在搜索的项目进行比较。您还需要两个变量来保存您要搜索的项目的最后一个(即最终)和倒数第二个(即倒数第二个)出现的列表中的索引。这两个变量的初始值都应为 -1(减一)。

    当您点击搜索项目的第一个匹配项时,更新最终索引变量。当您命中下一个匹配项时,将倒数第二个索引设置为最终索引,然后更新最终索引。

    对搜索到的项目的每个后续出现重复,即将倒数第二个索引设置为最终索引,然后将最终索引设置为列表中当前节点的索引。因此,如果搜索到的项目在列表中只出现一次,或者根本不出现,倒数第二个索引将为 -1。

    在编写递归方法时,首先需要的是一些将终止递归的条件。如果条件为真,则返回适当的值。如果条件为假,则更改方法参数并使用修改后的参数调用相同的方法。在您的情况下,终止条件是一个空节点。

    由于列表不是数组,你还需要跟踪当前节点的索引,以便能够从你的递归方法中返回它。

    这是我的实现。我创建了一个 LinkList 类,其中包含您的 Node 类的列表。 LinkList 类允许我最初创建一个链表。我还在NodeLinkList 类中添加了方法toString(),以帮助可视化列表的外观。 main() 方法用作递归方法的测试。递归方法的第一次调用使用列表中的第一个节点,其索引为 0(零)。

    public class Penultim {
    
        public static void main(String[] args) {
            LinkList list = new LinkList();
            list.append('a');
            list.append('b');
            list.append('a');
            list.append('b');
            list.append('c');
            list.append('d');
            list.append('e');
            list.append('f');
            list.append('b');
            System.out.println(list);
            System.out.println(list.getPenultimateOccurrenceIndex('b', list.getHead(), 0, -1, -1));
        }
    }
    
    class Node {
        private char item;
        private Node next;
    
        public Node(char item, Node next) {
            this.item = item;
            this.next = next;
        }
    
        public char getItem() {
            return item;
        }
    
        public Node getNext() {
            return next;
        }
    
        public void setNext(Node next) {
            this.next = next;
        }
    
        public String toString() {
            return item + "->";
        }
    }
    
    class LinkList {
        private Node head;
    
        public void append(char item) {
            if (head == null) {
                head = new Node(item, null);
            }
            else if (head.getNext() == null) {
                head.setNext(new Node(item, null));
            }
            else {
                Node node = head.getNext();
                while (node != null) {
                    if (node.getNext() == null) {
                        node.setNext(new Node(item, null));
                        break;
                    }
                    node = node.getNext();
                }
            }
        }
    
        public Node getHead() {
            return head;
        }
    
        public int getPenultimateOccurrenceIndex(char item,
                                                 Node node,
                                                 int ndx,
                                                 int penultimate,
                                                 int ultimate) {
            if (node == null) {
                return penultimate;
            }
            else {
                if (node.getItem() == item) {
                    if (ultimate >= 0) {
                        penultimate = ultimate;
                    }
                    ultimate = ndx;
                }
                return getPenultimateOccurrenceIndex(item,
                                                     node.getNext(),
                                                     ndx + 1,
                                                     penultimate,
                                                     ultimate);
            }
        }
    
        public String toString() {
            StringBuilder sb = new StringBuilder();
            Node node = head;
            while (node != null) {
                sb.append(node);
                node = node.getNext();
            }
            return sb.toString();
        }
    }
    

    运行上述代码时的输出是

    a->b->a->b->c->d->e->f->b->
    3
    

    【讨论】:

    • 成功了!我理解你在这里提出的逻辑 100%;自己创建它对我来说仍然非常困难,所以感谢您提供这个。到目前为止,在我的研究中,他们只向我们展示了简单的递归问题,所以我认为递归不应该像 getPenultimateOccurrenceIndex() 那样复杂。这只是告诉我它可能很复杂!
    【解决方案2】:

    我会以更小的步骤来做这件事。我会先写一个positionOfLastOccurrence(char letter)。将其编写为递归方法应该会教给您一些 positionOfSecondToLastOccurrence() 所需的技术。

    接下来的大部分挑战是帮助方法或方法的良好设计。我想我会写一个positionOfLastOccurrenceBeforePosition(int pos, char letter),它应该在位置pos之前返回最后一次出现letter的位置。因此,鉴于您的示例列表,ababcdefbpositionOfLastOccurrenceBeforePosition(0, 'b') 将返回 -1,positionOfLastOccurrenceBeforePosition(2, 'b') 将产生 1,positionOfLastOccurrenceBeforePosition(100, 'b') 将产生 8。我相信,这种方法也应该是递归的,因为这将是执行实际操作的方法工作到底。​​p>

    现在查找倒数第二个事件就是先查找最后一个事件,然后查找该事件之前的最后一个事件。

    【讨论】:

    • 最让我困惑的是如何在递归搜索时跟踪一个字母出现的实例数,因为该方法的每个实例一旦完成就会从内存中擦除。
    • 感谢您的解释;知道如何找到“更小的步骤”是我必须努力的事情。
    • 如果你按照我的建议(这不是解决问题的唯一方法),你不需要跟踪实例的数量。战斗愉快。 :-)
    猜你喜欢
    • 2019-06-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-12
    相关资源
    最近更新 更多