链表类常见面试/笔试题

链表类常见面试/笔试题:

1、链表的反转

2、链表是否有环路

3、环路的长度

4、环路的入口节点

5、找到单链表的倒数第k个节点

6、合并两个排序的列表

7、删除链表中重复的节点

8、删除链表中的某个节点

9、两个链表中的第一个公共节点

 

1、链表的反转

反转前:

反转后:

下面来谈谈如何对链表进行反转。

假设我们现在正在对结点v进行反转操作,即原来结点u的next域指向v(图中已经调整完毕,现在指向前一个结点),v的next域指向w。现在要做的是将v的next域指向u。从图中我们可以看出,当把v的next指针指向u的同时,原先指向的w就已经无法被正常的访问到了,为了避免“断链”,我们必须在指针更改指向之前,保存修改结点的下一结点。同时我们也必须存储上一个结点,因为next域即将修改指向该结点。因此定义三个指针,分别指向当前遍历的结点,前一个结点和后一个结点。

public class LinkListConverse {
    
    //链表的反转
    public void converse(LinkList head) {
        //定义当前节点 now,及相邻前节点pre
        LinkList now = head;
        LinkList pre = null;
        while (now!=null) {
            LinkList next = now.next;
            now.next = pre;    //调整指针,将指针调头
            //pre和now赋值向后一步走
            pre = now;    //游标后移
            now = next;    //游标后移
        }
    }

    public static void main(String[] args) {
        LinkList ln4 = new LinkList();
        ln4.data=4;
        ln4.next = null;
        
        LinkList ln3 = new LinkList();
        ln3.data=3;
        ln3.next = ln4;
        
        LinkList ln2 = new LinkList();
        ln2.data=2;
        ln2.next = ln3;
        
        LinkList ln1 = new LinkList();
        ln1.data=1;
        ln1.next = ln2;
        
        System.out.println("ln1-->ln"+ln1.next.data+"-->ln"+ln2.next.data+"-->ln"+ln3.next.data);
        
        LinkListConverse con = new LinkListConverse();
        con.converse(ln1);
        System.out.println("ln4-->ln"+ln4.next.data+"-->ln"+ln3.next.data+"-->ln"+ln2.next.data);
    }

}


2、链表是否有环路

设置两个指针,一快一慢,当有环路时,两者必相遇。

public class LinkCircleTest {
    
    public LinkList isHaveCircle(LinkList head) {
        LinkList one = head;
        LinkList two = head;
        while(two!=null && two.next!=null) {
            one = one.next;
            two = two.next.next;
            if (one == two) {
                System.out.println(one.data);
                return one;
            }
        }
        return null;
    }
    
    public static void main(String[] args) {
        
        LinkList ln8 = new LinkList();
        ln8.data=8;
        
        LinkList ln7 = new LinkList();
        ln7.data=7;
        ln7.next = ln8;
        
        LinkList ln6 = new LinkList();
        ln6.data=6;
        ln6.next = ln7;
        
        LinkList ln5 = new LinkList();
        ln5.data=5;
        ln5.next = ln6;
        
        LinkList ln4 = new LinkList();
        ln4.data=4;
        ln4.next = ln5;
        
        LinkList ln3 = new LinkList();
        ln3.data=3;
        ln3.next = ln4;
        
        ln8.next = ln3;
        
        LinkList ln2 = new LinkList();
        ln2.data=2;
        ln2.next = ln3;
        
        LinkList ln1 = new LinkList();
        ln1.data=1;
        ln1.next = ln2;
        
        LinkCircleTest c = new LinkCircleTest();
        c.isHaveCircle(ln1);
    }

3、环路的长度

假设两个指针在b点相遇。则点b必在环中,以b点为出发点,两个指针再来一次“追逐”,慢指针走一圈,快指针走2圈后他们又在b点相遇。此时慢指针走过的路程即为环周长。

    public int circleLength(LinkList node) {
        LinkList one = node;
        LinkList two = node;
        int i = 0;
        while (two!=null && two.next!=null) {
            one = one.next;
            two = two.next.next;
            i++;
            if (one == two)
                break;
        }
        return i;
    }

注:参数node为两指针在2中相遇的位置

4、环路的入口节点


根据前文的“公理”可得:a+nr+b=2(a+b),  其中r为圆周长,n>=1

化简得:a=nr-b, 即: a=(n-1)r+r-b

这个式子的意义就是,一个慢指针slower1从链表头出发,1个慢指针slower2从b点出发,slower1走到环入口时(路程为a),slower也刚好走到环入口(路程为(n-1)r+r-b:n-1个整圈加上r-b的路程)

所以求环的入口算法为:
    public LinkList getCircleDoor(LinkList head, LinkList node) {
        LinkList one1 = head;
        LinkList one2 = node;
        while (one1!=null && one2!=null) {
            one1 = one1.next;
            one2 = one2.next;
            if (one1 == one2) {
                return one1;
            }
        }
        return null;
    }


5、找到单链表的倒数第k个节点

为了能够只遍历一次就能找到倒数第k个节点,可以定义两个指针:

  (1)第一个指针从链表的头指针开始遍历向前走k-1,第二个指针保持不动

  (2)从第k步开始,第二个指针也开始从链表的头指针开始遍历

  (3)由于两个指针的距离保持在k-1,当第一个(走在前面的)指针到达链表的尾结点时,第二个指针(走在后面的)指针正好是倒数第k个结点

  下图展示了在有6个结点的链表上找倒数第3个结点的过程:

public LinkList findBackNode(LinkList head,int backnum) {
        LinkList first = head;
        LinkList two = head;
        for (int i=0;i             first = first.next;
        }
        while (first != null) {
            first = first.next;
            two = two.next;
        }
        return two;
    }


6、合并两个排序的列表

public class TowLinkCombine {
    
    public LinkList merge(LinkList head1,LinkList head2) {
        LinkList one = head1;
        LinkList two = head2;
        LinkList newLink = null;
        if (one == null) {
            return two;
        }
        if (two == null) {
            return one;
        }
        if (one !=null && two !=null) {
            if (one.data                 newLink = one;
                newLink.next = merge(one.next,two);
            } else {
                newLink = two;
                newLink.next = merge (one,two.next);
            }
        }
        return newLink;
    }

    public static void main(String[] args) {
        LinkList ln7 = new LinkList();
        ln7.data=7;
        ln7.next = null;
        
        LinkList ln6 = new LinkList();
        ln6.data=6;
        ln6.next = null;
        
        LinkList ln5 = new LinkList();
        ln5.data=5;
        ln5.next = ln7;
        
        LinkList ln4 = new LinkList();
        ln4.data=4;
        ln4.next = ln6;
        
        LinkList ln3 = new LinkList();
        ln3.data=3;
        ln3.next = ln5;
        
        LinkList ln2 = new LinkList();
        ln2.data=2;
        ln2.next = ln4;
        
        LinkList ln1 = new LinkList();
        ln1.data=1;
        ln1.next = ln3;
        
        TowLinkCombine comb = new TowLinkCombine();
        LinkList newLink = comb.merge(ln1, ln2);
        
        while(newLink!=null) {
            System.out.print("ln"+newLink.data+"->");
            newLink = newLink.next;
        }
    }
}


7、删除链表中重复的节点

删除链表中重复的节点
在一个排序,如何删除重复的节点?
例如:1 -> 2 -> 3 -> 3 -> 4
删除后是 1 -> 2 -> 3 -> 4

public void delSameNote(LinkList head) {
        LinkList pre = null;
        LinkList now = head;
        while (now != null) {
            LinkList next = now.next;
            pre = now;
            now = next;
            if (now !=null && now.data == pre.data) {
                pre.next = now.next;
            }
        }
    }


8、删除链表中的某个节点

原理并不是把当前节点从链表中删除,而是把下一个节点的值和指针赋给当前节点

public void nodeDelete (LinkList head,LinkList delNode) {
        LinkList list = head;
        while (list != null) {
            if (list == delNode) {
                list.data = list.next.data;
                list.next = list.next.next;
                break;
            }
            list = list.next;
        }
    }

9、两个链表中的第一个公共节点

用HashMap: 

第一个while是把pHead1的所有节点都放进去。

第二个while开始,对pHead2的每个节点都用  containsKey 方法来判断。 

你可能感兴趣的:(Java,笔试)