使用递归从两个链表中查找公共节点

发布于 2024-08-30 16:28:36 字数 294 浏览 2 评论 0原文

我必须编写一个方法,使用递归返回一个链表,其中包含两个链表共有的所有节点,无需循环。

例如,

第一个列表是 2 -> 5-> 7-> 10

第二个列表是 2 -> 4-> 8-> 10

将返回的列表是 2 -> 10

我对此毫无进展。我一直在想的是递归地检查第一个列表的每个值与第二个列表的每个值,但第二个列表每次都会被一个节点剪切,我无法比较下一个列表第一个列表中的值与第二个列表中的值。我希望这是有道理的...

任何人都可以帮忙吗?

I have to write a method that returns a linked list with all the nodes that are common to two linked lists using recursion, without loops.

For example,

first list is 2 -> 5 -> 7 -> 10

second list is 2 -> 4 -> 8 -> 10

the list that would be returned is 2 -> 10

I am getting nowhere with this.. What I have been think of was to check each value of the first list with each value of the second list recursively but the second list would then be cut by one node everytime and I cannot compare the next value in the first list with the the second list. I hope this makes sense...

Can anyone help?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

划一舟意中人 2024-09-06 16:28:36

只有当每个列表中的值都已排序时,这个问题才有意义。如果是这种情况,那么这将递归地查找重复项(以伪代码)

Node merge(Node n1, Node n2) {
   IF n1 == null OR n2 == null
      RETURN null
   ELSE IF n1.value == n2.value
      Node dupNode(n1.value);
      dupNode.next = merge(n1.next, n2.next);
      RETURN dupNode;
   ELSE IF n1.value < n2.value
      RETURN merge(n1.next, n2)
   ELSE
      RETURN merge(n1, n2.next)
}

给定长度 L1L2 的列表,这会将它们合并为 O(L1 + L2)。它通过为重复项创建新节点来非破坏性地实现这一点。如果您愿意,您可以轻松地将其修改为从列表之一“窃取”。

This question only has weight in it if the values in each list are sorted. If that's the case, then this will find duplicates recursively (in pseudocode)

Node merge(Node n1, Node n2) {
   IF n1 == null OR n2 == null
      RETURN null
   ELSE IF n1.value == n2.value
      Node dupNode(n1.value);
      dupNode.next = merge(n1.next, n2.next);
      RETURN dupNode;
   ELSE IF n1.value < n2.value
      RETURN merge(n1.next, n2)
   ELSE
      RETURN merge(n1, n2.next)
}

Given a list of length L1 and L2, this will merge them in O(L1 + L2). It does so non-destructively, by creating new nodes for the duplicates. You can easily modify it to "steal" from one of the lists if you wish.

入画浅相思 2024-09-06 16:28:36

这个问题取决于约束条件。

最简单、最幼稚的解决方案是,如果您有两个大小为 n 的元素,则迭代一个列表并将其与第二个列表中的每个项目进行比较。

解决方案:O(n2)

但当然你可以做得更好。

现在,如果您有一个可用的 HashSet (或其他接近 O(1))的数据结构,那么您可以执行以下操作:

迭代一个列表。将每个元素添加到集合中。迭代第二个列表。如果该元素在集合中,则将其添加到结果列表中。

解:O(n)

This problem depends on the constraints.

The simplest, most naive solution is if you have two elements of size n, you iterate over one list and compare it to every item in the second list.

Solution: O(n2)

But of course you can do much better.

Now, if you have a HashSet (or other near-O(1)) data structure available then this is what you can do:

Iterate over one list. Add each element to the set. Iterate over the second list. If the element is in the set then add it to the result list.

Solution: O(n)

天赋异禀 2024-09-06 16:28:36

如果链表已经排序,那么您可以非常有效地应用递归
这是来自 GeeksforGeeks

http://www.geeksforgeeks.org/intersection-两个排序链接列表/
看第三个选项。

struct node *sortedIntersect(struct node *a, struct node *b)
{
    /* base case */
    if (a == NULL || b == NULL)
        return NULL;

    /* If both lists are non-empty */

    /* advance the smaller list and call recursively */
    if (a->data < b->data)
        return sortedIntersect(a->next, b);

    if (a->data > b->data)
        return sortedIntersect(a, b->next);

    // Below lines are executed only when a->data == b->data
    struct node *temp = (struct node *)malloc(sizeof(struct node));
    temp->data = a->data;

    /* advance both lists and call recursively */
    temp->next = sortedIntersect(a->next, b->next);
    return temp;
}

If the linked list is already sorted, than you can apply recursion very effectively
this is from GeeksforGeeks

http://www.geeksforgeeks.org/intersection-of-two-sorted-linked-lists/
look at the 3rd option.

struct node *sortedIntersect(struct node *a, struct node *b)
{
    /* base case */
    if (a == NULL || b == NULL)
        return NULL;

    /* If both lists are non-empty */

    /* advance the smaller list and call recursively */
    if (a->data < b->data)
        return sortedIntersect(a->next, b);

    if (a->data > b->data)
        return sortedIntersect(a, b->next);

    // Below lines are executed only when a->data == b->data
    struct node *temp = (struct node *)malloc(sizeof(struct node));
    temp->data = a->data;

    /* advance both lists and call recursively */
    temp->next = sortedIntersect(a->next, b->next);
    return temp;
}
风向决定发型 2024-09-06 16:28:36

如果您不关心重复项,那么使用 Set 的内置 keepAll() 方法是一个简单的解决方案。

  List<T> list1 = ...; // The smaller list
  List<T> list2 = ...; 

  ...
  final Set<T> s1 = new HashSet<T>(list1);
  s1.retainAll(list2); 
  // Try s1.retainAll(new HashSet<T>(list2)); if the lists are really bug

  final List<T> solution = new LinkedList(s1);

If you do not care about duplicates using Set's built-in retainAll() method is an easy solution.

  List<T> list1 = ...; // The smaller list
  List<T> list2 = ...; 

  ...
  final Set<T> s1 = new HashSet<T>(list1);
  s1.retainAll(list2); 
  // Try s1.retainAll(new HashSet<T>(list2)); if the lists are really bug

  final List<T> solution = new LinkedList(s1);
°如果伤别离去 2024-09-06 16:28:36

有很多方法可以解释这个问题。我们是在寻找列表表示的集合的交集,还是在寻找最长的公共子序列?列表总是排序的吗?

在我的递归解决方案中,我假设我们正在寻找一些最长的子序列,并且我不假设有关项目顺序的任何内容:

private static <T> List<T> longestCommonSubseq(List<T> a, int indA, List<T> b, int indB){
    if (indA == a.size() || indB == b.size())
        return Collections.emptyList();

    T itemA = a.get(indA);
    T itemB = b.get(indB);

    List<T> res;
    if (itemA.equals(itemB)){
        res = new ArrayList<T>();
        res.add(itemA);
        res.addAll(longestCommonSubseq(a, indA+1, b, indB+1));
    }else{
        List<T> opt1 = longestCommonSubseq(a, indA+1, b, indB);
        List<T> opt2 = longestCommonSubseq(a, indA, b, indB+1);
        if (opt1.size()>opt2.size())
            res = opt1;
        else
            res = opt2;
    }
    return res;
}

public static <T> List<T> longestCommonSubseq(List<T> a, List<T> b){
    return longestCommonSubseq(a,0,b,0);
}

注意:为了简单起见,在我的解决方案中,列表应该是随机访问的(例如ArrayList)。

There are many ways to interpret the question. Are we looking for an intersection of the sets represented by the lists, or are we looking for a longest common subsequence? are the lists always sorted?

In my recursive solution, I assume that we are looking for some longest subsequence, and I don't assume anything about the items order:

private static <T> List<T> longestCommonSubseq(List<T> a, int indA, List<T> b, int indB){
    if (indA == a.size() || indB == b.size())
        return Collections.emptyList();

    T itemA = a.get(indA);
    T itemB = b.get(indB);

    List<T> res;
    if (itemA.equals(itemB)){
        res = new ArrayList<T>();
        res.add(itemA);
        res.addAll(longestCommonSubseq(a, indA+1, b, indB+1));
    }else{
        List<T> opt1 = longestCommonSubseq(a, indA+1, b, indB);
        List<T> opt2 = longestCommonSubseq(a, indA, b, indB+1);
        if (opt1.size()>opt2.size())
            res = opt1;
        else
            res = opt2;
    }
    return res;
}

public static <T> List<T> longestCommonSubseq(List<T> a, List<T> b){
    return longestCommonSubseq(a,0,b,0);
}

Note: For simplicity, in my solutions the lists should be random access (e.g. ArrayList).

心欲静而疯不止 2024-09-06 16:28:36

好吧,除了你的要求之外,我不会对你想要的做任何假设。下面是一个递归函数,它查找两个链表的公共元素。这需要 O(n^2) 时间,这就是你通过设置得到的结果。

请注意,虽然这是尾递归,但 Java(通常)不会对其进行优化,因此这会导致长列表的堆栈崩溃。

    import java.util.*;

    public class CommonNodeLinkedList {
        public static void main(String[] args) {
            List<Integer> list1_items = Arrays.asList(2, 5, 7, 10);
            List<Integer> list2_items = Arrays.asList(2, 4, 8, 10);

            LinkedList<Integer> list1 = new LinkedList<Integer>();
            list1.addAll(list1_items);
            LinkedList<Integer> list2 = new LinkedList<Integer>();
            list2.addAll(list2_items);

            System.out.println("List 1      : " + list1);
            System.out.println("List 2      : " + list2);
            System.out.println("Common Nodes: " + findCommonNodes(list1, list2));
        }

        public static LinkedList<Integer> findCommonNodes(LinkedList<Integer> list1,
LinkedList<Integer> list2) {
            return findCommonNodes_helper(list1, list2, new LinkedList<Integer>());
        }

        public static LinkedList<Integer> findCommonNodes_helper(LinkedList<Integer> list1,
LinkedList<Integer> list2,
LinkedList<Integer> result) {
            if (list1.isEmpty()) return result;
            Integer head = list1.pop();
            if (list2.contains(head)) {
                result.add(head);
            }
            return findCommonNodes_helper(list1, list2, result);
        }

    }

Ok, I'm not making any assumptions about what you want beyond what you asked for. Below is a recursive function which finds common elements of two linked lists. It takes O(n^2) time, what that what you get with your setup.

Note that while this is tail-recursive, Java (generally) doesn't optimize that so this will blow the stack for long lists.

    import java.util.*;

    public class CommonNodeLinkedList {
        public static void main(String[] args) {
            List<Integer> list1_items = Arrays.asList(2, 5, 7, 10);
            List<Integer> list2_items = Arrays.asList(2, 4, 8, 10);

            LinkedList<Integer> list1 = new LinkedList<Integer>();
            list1.addAll(list1_items);
            LinkedList<Integer> list2 = new LinkedList<Integer>();
            list2.addAll(list2_items);

            System.out.println("List 1      : " + list1);
            System.out.println("List 2      : " + list2);
            System.out.println("Common Nodes: " + findCommonNodes(list1, list2));
        }

        public static LinkedList<Integer> findCommonNodes(LinkedList<Integer> list1,
LinkedList<Integer> list2) {
            return findCommonNodes_helper(list1, list2, new LinkedList<Integer>());
        }

        public static LinkedList<Integer> findCommonNodes_helper(LinkedList<Integer> list1,
LinkedList<Integer> list2,
LinkedList<Integer> result) {
            if (list1.isEmpty()) return result;
            Integer head = list1.pop();
            if (list2.contains(head)) {
                result.add(head);
            }
            return findCommonNodes_helper(list1, list2, result);
        }

    }
素罗衫 2024-09-06 16:28:36

有两个链接列表如下:

1--->2--->3--->4--->5--->6--->7--->2 8

a--->b--->c--->5--->6--->7--->8

然后我们需要找出合并节点。

算法:

  1. 计算第一个链接列表的长度,假设它是“len1”。
  2. 计算第二个链接列表的长度,假设它是“len2”。
  3. 找出 len1 和 len2 中较大的长度。在给定的示例中 len1 >长度2。
  4. 找出 len1 和 len2 的正差,在给定示例 |len1 - len2| 中
  5. 现在在大链接列表上取出 1 个指针 (ptr1),并将其放在 |len1 - len2| 上。从一开始的位置。
  6. 取1个指针(ptr2),放在链表2的开头,
  7. 将两个指针一一增加,并检查它们,如果相遇则为两个链表的合并点。

给定示例的算法:
1. 长度1=8
2. 长度2 = 7
3. len1>长度2
4.| len1 - len2 | = 1
5. ptr1 = 2 第一个链表的节点
6. ptr2 = 第二个链表的1个节点
7. 在链表1中,链表2中的3rd-->next和c-->next将指向同一个节点,即第4个节点,因此它是合并节点。

There are two link list like below:

1--->2--->3--->4--->5--->6--->7--->8

a--->b--->c--->5--->6--->7--->8

Then we need to find out the merging node.

Algo:

  1. Calculate the length of first Link List, lets say it is "len1".
  2. Calculate the length of second Link List, lets say it is "len2".
  3. Find out the greater length out of len1 and len2. in the given example len1 > len2.
  4. Find out the positive difference of len1 and len2, in given example |len1 - len2|
  5. Now take 1 pointer (ptr1) on the big link list and place it on the |len1 - len2| position from the start.
  6. Take 1 pointer (ptr2), and put it on the start of Link list 2.
  7. increase both pointer one by one, and check them, if they meet then that is the merging point of two link lists.

Algo with Given example:
1. len1 = 8
2. len2 = 7
3. len1 > len2
4. | len1 - len2 | = 1
5. ptr1 = 2 node of first link list
6. ptr2 = 1 node of second link list
7. in link list1, 3rd-->next and c-->next in link list2 will be pointing to same node, which is 4th node, hence it is the merging node.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文