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

时间:2010-04-25 06:25:46

标签: java algorithm recursion

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

例如,

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

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

将返回的列表是2 - > 10

我无处可去..我一直想到的是用递归的方式检查第一个列表的每个值和第二个列表的每个值,但是第二个列表每次都会被一个节点切断,我无法比较带有第二个列表的第一个列表中的下一个值。我希望这是有道理的......

有人可以帮忙吗?

7 个答案:

答案 0 :(得分:5)

如果对每个列表中的值进行排序,则此问题仅具有权重。如果是这种情况,那么这将以递归方式(在伪代码中)找到重复项

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)中。它通过为重复项创建新节点而非破坏性地完成。如果您愿意,可以轻松地将其修改为从其中一个列表中“窃取”。

答案 1 :(得分:2)

此问题取决于约束。

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

解决方案:O(n 2

但当然你可以做得更好。

现在,如果您有HashSet(或其他近O(1))数据结构,那么您可以这样做:

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

解决方案:O(n)

答案 2 :(得分:2)

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

http://www.geeksforgeeks.org/intersection-of-two-sorted-linked-lists/ 看看第3个选项。

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;
}

答案 3 :(得分:0)

如果你不关心重复使用Set的内置retainAll()方法是一个简单的解决方案。

  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);

答案 4 :(得分:0)

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

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

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)。

答案 5 :(得分:0)

好吧,除了你的要求之外,我不会对你想要的东西做任何假设。下面是一个递归函数,它找到两个链表的共同元素。它需要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);
        }

    }

答案 6 :(得分:0)

有以下两个链接列表:

1 ---→2 ---→3 ---→4 ---→5 ---→6 ---大于7 ---&GT; 8

一个---&GT; b ---&以及c ---→5 ---→6 ---大于7 ---&GT; 8

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

ALGO:

  1. 计算第一个链接列表的长度,假设它是“len1”。
  2. 计算第二个链接列表的长度,假设它是“len2”。
  3. 找出len1和len2的更长的长度。在给定的例子中,len1&gt; LEN2。
  4. 找出len1和len2的正差,在给定的例子中| len1 - len2 |
  5. 现在在大链接列表中取1指针(ptr1)并将其放在| len1 - len2 |上从一开始的位置。
  6. 取1指针(ptr2),并将其放在链接列表2的开头。
  7. 逐个增加两个指针,并检查它们是否符合,这是两个链接列表的合并点。
  8. Algo以给定的例子: 1. len1 = 8 2. len2 = 7 3. len1&gt; LEN2 4. | len1 - len2 | = 1 5. ptr1 =第一个链接列表的2个节点 6. ptr2 =第二链接列表的1个节点 7.在链接list1,3rd - &gt; next和c - &gt;链接list2中的next将指向同一个节点,即第4个节点,因此它是合并节点。