• 链表相关考题


    1.打印有序链表的公共值

      问题描述:

        现有两个升序链表,且链表中均无重复元素。请设计一个高效的算法,打印两个链表的公共值部分。

        给定两个链表的头指针headAheadB,请返回一个vector,元素为两个链表的公共部分。请保证返回数组的升序。两个链表的元素个数均小于等于500。保证一定有公共                   值测试样例:

        {1,2,3,4,5,6,7},{2,4,6,8,10}
        返回:[2.4.6]
      
     方法:两个头指针分别指向表头,哪个结点元素小,哪个指针前移,如果相同,则都前移,任意一个链表走完,函数停止。
    public int[] findCommonParts(ListNode headA, ListNode headB) {
            // write code here
            List<Integer> arr=new ArrayList<Integer>();
            if(headA==null||headB==null) return null;
            while(headA!=null&&headB!=null){
                if(headA.val==headB.val) 
                {arr.add(headA.val);
                 headA=headA.next;
                 headB=headB.next;
                }else if(headA.val<headB.val) headA=headA.next;
                else
                    headB=headB.next;
            }
            int[] array=new int[arr.size()];
            for(int i=0;i<arr.size();i++) array[i]=arr.get(i);
            return array;
        }


    2.用栈完成链表的K逆序  

    问题:

      有一个单链表,请设计一个算法,使得每K个节点之间逆序,如果最后不够K个节点一组,则不调整最后几个节点。例如链表1->2->3->4->5->6->7->8->null,K=3这个例子。调            整后为,3->2->1->6->5->4->7->8->null。因为K==3,所以每三个节点之间逆序,但其中的7,8不调整,因为只有两个节点不够一组。

      给定一个单链表的头指针head,同时给定K值,返回逆序后的链表的头指针。

    方法:利用栈的特性,对k个元素进行反转

    public ListNode inverse(ListNode head, int k) {
            // write code here
            ListNode[] stk=new ListNode[k];
            int top=-1;
            ListNode current=head;
            ListNode lastGroupHead=new ListNode(-1);
            ListNode newHead=lastGroupHead;
            while(current!=null){
                if(top==k-1){
                    while(top!=-1){
                        lastGroupHead=lastGroupHead.next=stk[top--];
                    }
                }else{
                    stk[++top]=current;
                    current=current.next;
                }
            }
            if(top==k-1){
                 while(top!=-1)
                     lastGroupHead=lastGroupHead.next=stk[top--];
            }else{
                for(int i=0;i<=top;i++) 
                     lastGroupHead=lastGroupHead.next=stk[i];
            }lastGroupHead.next=null;
            return newHead.next;
        }

     

    3.判断一个链表是否为回文结构:

      方法1:T=O(n),S=O(n), 利用栈把链表每个元素入栈,然后依次出栈和链表元素对比。

      方法2:T=O(n/2),S=O(n),设置两个指针,一个快指针(一次前进两步),一个慢指针,目的是找到链表的中间的位置。

          分析:当链表元素个数为奇数时,快指针.next=null时(一定会走到.next=null),则此时移动后的慢指针就是中间位置。

             当偶数时,快指针=null时(必然会走到null),移动前的慢指针就是中间两个元素的左边位置。

            当得到中间位置的指针时,只需将一半的链表入栈,进行对比。

      方法3:T=O(n),S=O(1),将后半部分指针翻转,如 1->2->3->2->1 变换成1->2->3<-2<-1,用右半部分和左半部分判断。

        

    public static boolean isPalindrome(ListNode pHead) {
            ListNode slow=pHead;
            ListNode fast=pHead;
            while(fast!=null&&fast.next!=null) {
                fast=fast.next.next;
                slow=slow.next;
            }
            
            ListNode right;
         //从slow开始翻转(如果是偶数,如1,2,3,3,2,1,奇数时如1,2,3,2,1 右半部分都是1,2,3
         //无论是奇是偶,只需把右半部分比较完即可 right
    =reverse(slow); ListNode current=pHead;
    while(right!=null) { if(current.val!=right.val) return false; current=current.next; right=right.next; } return true; }

    //翻转右半部分
    public static ListNode reverse(ListNode head) { ListNode n1=head; ListNode current=head.next; n1.next=null; ListNode n2=current; while(current!=null) { n2=current; ListNode tmp=current.next; n2.next=n1; n1=current; current=tmp; } return n2; }

    4.复杂链表的复制

      问题描述:输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回一个链表的拷贝。

      方法图解:

        

     代码:

     public RandomListNode Clone(RandomListNode pHead)
        {
            RandomListNode cur=pHead;
            while(cur!=null){
                RandomListNode tmp=cur.next;
                RandomListNode cp=new RandomListNode(cur.label);
                cp.next=cur.next;
                cur.next=cp;
                cur=tmp;
            }
            cur=pHead; 
            while(cur!=null){
                if(cur.random==null) cur.next.random=null;
                else cur.next.random=cur.random.next;     
                cur=cur.next.next;         
            }
            RandomListNode newHead=new RandomListNode(-1);
            RandomListNode newcur=newHead;
            cur=pHead;
            
            while(cur!=null){
                newcur.next=cur.next;
                newcur=newcur.next;
                cur.next=cur.next.next;
                cur=cur.next;
            }
            return newHead.next;
        }    

    5.链表判断否是有环

      问题:如何判断一个单链表是否有环?有环的话返回进入环的第一个节点的值,无环的话返回-1。

          如果链表的长度为N,请做到时间复杂度O(N),额外空间复杂度O(1)。

      分析:如果不做空间上的限制,可以使用哈希表来辅助,当一个节点重复出现时,即是环的入口。

         当限制空间时,采用两个指针,快和慢,当快指针和慢指针相交时,即表示有环,此时让快指针回头开始位置,两个指针每次走一步,

         当相交时,即进入环(此方法的数学证明略)

      代码:

     public int chkLoop(ListNode head, int adjust) {
            // write code here
            ListNode slow=head;
            ListNode fast=head;
            while(fast!=null&&fast.next!=null){
                slow=slow.next;
                fast=fast.next.next;
                if(slow==fast){
                    fast=head;
                    while(slow!=fast){
                        fast=fast.next;
                        slow=slow.next;
                    }
                    return fast.val;
                }
            }
            return -1;
        }

    6.无环链表判断相交

    问题:

      现在有两个无环单链表,若两个链表的长度分别为m和n,请设计一个时间复杂度为O(n + m),额外空间复杂度为O(1)的算法,判断这两个链表是否相交

    分析:

      由于链表相交,则必然最后会有公共部分,故可以直接判断最后一个节点是否相同。

     若要找到第一个交点,则需让较长的链表先走n2-n1步,然后两链表同步走,直到相交

    代码:

    public boolean chkIntersect(ListNode headA, ListNode headB) {
            // write code here
            ListNode lastA=headA;
            while(lastA.next!=null) lastA=lastA.next;
            ListNode lastB=headB;
            while(lastB.next!=null) lastB=lastB.next;
            
            return lastA==lastB;
        }

    7.有环链表判断相交

    问题:

      如何判断两个有环单链表是否相交?相交的话返回第一个相交的节点,不想交的话返回空。如果两个链表长度分别为N和M,请做到时间复杂度O(N+M),额外空间复杂度O(1)。

    分析:

      首先取得带环链表的环入口,如果两入口相等,则有1,2两种情况,否则有3,4两种情况。

    代码:

    public boolean chkInter(ListNode head1, ListNode head2, int adjust0, int adjust1) {
            // write code here
            ListNode entry1=chkLoop(head1,0);
            ListNode entry2=chkLoop(head2,0);
            if(entry1==null||entry2==null) return false;
            if(entry1==entry2){
               return true; 
            }else{
                ListNode tmp=entry2.next;
                while(tmp!=entry2){
                    if(tmp==entry1) return true;
                    tmp=tmp.next;
                }
                return false;
            }
        }

    8.链表判断相交

       综合已上几种情况,分为链表都有环和都无环进行考虑,其他情况则不可能相交

  • 相关阅读:
    JVM Inline
    Lattice
    编译技术
    sql-server-on-linux
    concurrency 方面的books
    Linux debugger lldb
    javaperformanceoptimization
    Understanding The Linux Virtual Memory Manager
    web performance tu ning
    linux io architecture
  • 原文地址:https://www.cnblogs.com/lshao/p/9032252.html
Copyright © 2020-2023  润新知