链表

1环形链表插值

有一个整数val,如何在节点值有序的环形链表中插入一个节点值为val的节点,并且保证这个环形单链表依然有序。

给定链表的信息,及元素的值A及对应的nxt指向的元素编号同时给定val,请构造出这个环形链表,并插入该值。

测试样例:
[1,3,4,5,7],[1,2,3,4,0],2
返回:{1,2,3,4,5,7}

思路:判断链表是否为空,为空,直接返回head即可
不为空,如果head.val>=val,将只插到head之前
设置preNode,nextNode,若curNode在preNode和nextNode之间,插入
import java.util.*;
 
/*
public class ListNode {
    int val;
    ListNode next = null;
 
    ListNode(int val) {
        this.val = val;
    }
}*/
public class InsertValue {
    public ListNode insert(int[] A, int[] nxt, int val) {
        // write code here
        if(A.length == 0){
            ListNode curNode = new ListNode(val);
            //curNode.next= curNode;
            return curNode;
        }
        //构造环形链表
        int len = A.length;
        ListNode head= new ListNode(A[0]);
         ListNode tail = head;
        for(int i=0;i<len-1;i++){
            ListNode curNode = new ListNode(A[nxt[i]]);
            tail.next = curNode; 
            tail = curNode;
        }
         //tail.next = head;
        
         
        //插入值
        ListNode preNode = head;
        ListNode nextNode = preNode.next;
        if(head.val>=val){
            ListNode curNode = new ListNode(val);
            curNode.next = head;
            //tail.next = curNode;
            return curNode;
        }
        while(nextNode!=null&&val>nextNode.val){
            preNode = nextNode;
            nextNode = preNode.next;
        }
         
        ListNode curNode = new ListNode(val);
        curNode.next = nextNode;
        preNode.next = curNode;
        return head;
         
    }
}

2访问单个节点的删除

实现一个算法,删除单向链表中间的某个结点,假定你只能访问该结点。

给定带删除的节点,请执行删除操作,若该节点为尾节点,返回false,否则返回true

思路:判断该节点的next节点,如果为空,返回false,如果不为空,将next节点值复制给该节点,且将该节点的next赋值为next的next

import java.util.*;
 
/*
public class ListNode {
    int val;
    ListNode next = null;
 
    ListNode(int val) {
        this.val = val;
    }
}*/
public class Remove {
    public boolean removeNode(ListNode pNode) {
        // 特殊情况,如果是尾结点,删除操作不成功!
        if(pNode.next == null) {
            return false;
        }
         
        pNode.val = pNode.next.val;
        // 可以不用临时变量
        pNode.next = pNode.next.next;
        // 注意返回值必须写
        return true;
    }
}

3链表的分化

对于一个链表,我们需要用一个特定阈值完成对它的分化,使得小于等于这个值的结点移到前面,大于该值的结点在后面,同时保证两类结点内部的位置关系不变。

给定一个链表的头结点head,同时给定阈值val,请返回一个链表,使小于等于它的结点在前,大于等于它的在后,保证结点值不重复。

测试样例:
{1,4,2,5},3
{1,2,4,5}

思路:将链表分为2个,smallerList和biggerList,如果值<=val,放到小链表,反之放到大链表,最后整体串联起来
import java.util.*;
 
/*
public class ListNode {
    int val;
    ListNode next = null;
 
    ListNode(int val) {
        this.val = val;
    }
}*/
public class Divide {
    public ListNode listDivide(ListNode head, int val)
    {
        if(head == null || head.next == null)    return head;
 
        ListNode node = head, smallerList = null, biggerList = null;
        ListNode tmp = null, smallerListTail = null, biggerListTail = null;
        while (node != null)
        {
            tmp = node;
            node = node.next;
 
            tmp.next = null;
            int value = tmp.val;
            if(value <= val)
            {
                if(smallerList == null)
                    smallerList = tmp;
                else
                    smallerListTail.next = tmp;
                smallerListTail = tmp;
            }
            else
            {
                if(biggerList == null)
                    biggerList = tmp;
                else
                    biggerListTail.next = tmp;
                biggerListTail = tmp;
            }
        }
        if(smallerListTail == null)
            return biggerList;
        else if(biggerList == null)
            return smallerList;
        smallerListTail.next = biggerList;
        return smallerList;
    }
}

4打印两个链表的公共值

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

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

测试样例:
{1,2,3,4,5,6,7},{2,4,6,8,10}
返回:[2.4.6]

思路:如果两个链表有任何一个为空,则返回null
反之,依次比较两个节点值,不等移动,相等记录到ArrayList集合中,那个小向下一个节点移动
import java.util.*;
 
/*
public class ListNode {
    int val;
    ListNode next = null;
 
    ListNode(int val) {
        this.val = val;
    }
}*/
public class Common {
    public int[] findCommonParts(ListNode headA, ListNode headB) {
        // write code here
        if(headA == null || headB == null)
            return null;
         
        List<Integer> list = new ArrayList<Integer>();
         
        while(headA != null && headB != null) {
            if(headA.val < headB.val)
                headA = headA.next;
             
            else if(headA.val > headB.val)
                headB = headB.next;
             
            else if(headA.val == headB.val) {
                list.add(headA.val);
                headA = headA.next;
                headB = headB.next;
            }
        }
        int[] res = new int[list.size()];
        for(int i = 0; i < list.size(); i++) {
            res[i] = list.get(i);
        }
         
        return res;
    }
}

5链表的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值,返回逆序后的链表的头指针。

import java.util.*;
 
/*
public class ListNode {
    int val;
    ListNode next = null;
 
    ListNode(int val) {
        this.val = val;
    }
}*/
public class KInverse {
    public ListNode inverse(ListNode head, int k) {
        ListNode cur = head;
        int count = 0;
        while(cur!=null && count!=k) {
            cur = cur.next;
            count++;
        }
        //此时cur为第k+1个节点
        if(count==k) {
            cur = inverse(cur,k);
            while(count-- >0) {
                ListNode tmp = head.next;
                head.next = cur;
                cur = head;
                head = tmp;
            }
            //cur为翻转后的第一个节点
            head = cur;
        }
        return head;
    }
}

栈实现

import java.util.*;
 
/*
public class ListNode {
    int val;
    ListNode next = null;
 
    ListNode(int val) {
        this.val = val;
    }
}*/
public class KInverse {
    public ListNode inverse(ListNode head, int k) {
        // write code here
        Stack<Integer> stack = new Stack<Integer>();
        stack.push(head.val);
        int count = 1;
        ListNode curHead = head;
        ListNode temp = head;
        while(temp.next != null) {
            temp = temp.next;
            stack.push(temp.val);
            count++;
            if(count == k) {
                while(!stack.isEmpty()) {
                    curHead.val = stack.pop();
                    curHead = curHead.next;
                }
                count = 0;
            }
        }
        return head;
    }
}

6链表指定值清除

现在有一个单链表。链表中每个节点保存一个整数,再给定一个值val,把所有等于val的节点删掉。

给定一个单链表的头结点head,同时给定一个值val,请返回清除后的链表的头结点,保证链表中有不等于该值的其它值。请保证其他元素的相对顺序。

测试样例:
{1,2,3,4,3,2,1},2
{1,3,4,3,1}

思路:判断这个节点,为头节点
非头非尾节点
尾节点
import java.util.*;
 
/*
public class ListNode {
    int val;
    ListNode next = null;
 
    ListNode(int val) {
        this.val = val;
    }
}*/
public class ClearValue {
    public ListNode clear(ListNode head, int val) {
        // write code here
         
        ListNode cur = head;
        ListNode pre = cur;
         
        while(head != null && head.val == val) {
            head = head.next;
            cur = head;
            pre = cur;
        }
         
        //删除元素非头节点
        while(cur.next != null) {
            cur = cur.next;
            if(cur.val == val) {
                if(cur.next == null) {
                    pre.next = null;
                } else {
                   pre.next = cur.next;  
                   cur = pre;
                }
            }
            pre = cur;
        }
        return head;
    }
}

7链表的回文结构

请编写一个函数,检查链表是否为回文。

给定一个链表ListNode* pHead,请返回一个bool,代表链表是否为回文。

测试样例:
{1,2,3,2,1}
返回:true
{1,2,3,2,3}
返回:false
import java.util.*;
 
/*
public class ListNode {
    int val;
    ListNode next = null;
 
    ListNode(int val) {
        this.val = val;
    }
}*/
public class Palindrome {
    public boolean isPalindrome(ListNode pHead) {
        if(pHead == null) return true;
        ListNode slow = pHead;
        ListNode fast = pHead;
        while(fast.next!=null && fast.next.next!=null) {
            slow = slow.next;
            fast = fast.next.next;
        }
        //如果是奇数节点,此时slow为中间那个节点;如果是偶数节点,此时slow为前半段最后一个节点
        ListNode rhead = slow.next;
        slow.next = null;
        //对rhead开始的链表进行翻转
        ListNode pre = null;
        while(rhead!=null) {
            ListNode tmp = rhead.next;
            rhead.next = pre;
            pre = rhead;
            rhead = tmp;
        }
        //此时pre为翻转后的头节点
        while(pre!=null && pHead!=null) {
            if(pre.val != pHead.val) {
                return false;
            }
            pre = pre.next;
            pHead = pHead.next;
        }
        return true;
    }
}

用了栈

import java.util.*;
 
/*
public class ListNode {
    int val;
    ListNode next = null;
 
    ListNode(int val) {
        this.val = val;
    }
}*/
public class Palindrome {
    public boolean isPalindrome(ListNode pHead) {
        // write code here
        Stack<Integer> s = new Stack<Integer>();
        ListNode mynode = pHead;
        while(mynode != null){
            s.push(mynode.val);
            mynode = mynode.next;
        }
        int i = (int)s.size()/2;
        mynode = pHead;
        for(; i > 0; i--){
            if(mynode.val != s.pop()){
                return false;
            }
            mynode = mynode.next;
        }
        return true;
    }
}

8复杂链表的复制

输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点)。

思路:链表元素复制

        为复制后的元素加上Rand指针

        分开原来的指针和复制后的指针

/*
public class RandomListNode {
    int label;
    RandomListNode next = null;
    RandomListNode random = null;
 
    RandomListNode(int label) {
        this.label = label;
    }
}
*/
public class Solution {
    public RandomListNode Clone(RandomListNode pHead)
    {
        if(pHead==null) return pHead;
        RandomListNode node = pHead;
        RandomListNode tmp = null;
        while(node!=null){ //拷贝
            tmp = node.next;           
            node.next = new RandomListNode(node.label);
            node.next.next = tmp;
            node = tmp;
        }
        node = pHead;
        RandomListNode nodeCopy = null;
        while(node!=null){//拷贝节点random指针
            tmp = node.next.next;
            nodeCopy = node.next;
            nodeCopy.random = (node.random==null)?null: node.random.next;
            node = tmp;
        }
        node = pHead;
        RandomListNode resHead = pHead.next;
        while(node!=null){//分离出两个链表
            tmp = node.next.next;
            nodeCopy = node.next;
            node.next = tmp;
            nodeCopy.next = (tmp==null)?null:tmp.next;
            node = tmp;
        } 
        return resHead;
    }
}

 

/*
public class RandomListNode {
    int label;
    RandomListNode next = null;
    RandomListNode random = null;
 
    RandomListNode(int label) {
        this.label = label;
    }
}
*/
public class Solution {
    public RandomListNode Clone(RandomListNode pHead) {
        if(pHead==null) return null;
        RandomListNode cur = pHead;
        //在原有链表后面复制节点
        while(cur!=null) {
            RandomListNode tmp = new RandomListNode(cur.label);
            tmp.next = cur.next;
            cur.next = tmp;
            cur = tmp.next;
        }
        //完成随机指针
        cur = pHead;
        while(cur!=null) {
            if(cur.random!=null) {
                cur.next.random = cur.random;
            }
            cur = cur.next.next;
        }
         RandomListNode nhead = pHead.next;
        cur = pHead;
        //第三次遍历 将链表分离
        while(cur!=null) {
            RandomListNode tmp = cur.next;
            cur.next = tmp.next;
            if(tmp.next!=null) {
                tmp.next = tmp.next.next;
            }
            cur = cur.next;
        }
        return nhead;
    }
}

9链表判环

如何判断一个单链表是否有环?有环的话返回进入环的第一个节点的值,无环的话返回-1。如果链表的长度为N,请做到时间复杂度O(N),额外空间复杂度O(1)。

给定一个单链表的头结点head(注意另一个参数adjust为加密后的数据调整参数,方便数据设置,与本题求解无关),请返回所求值。

思路:快慢指针,快指针,一次走2步,慢指针一次走1步,慢指针为空,无环,返回null

        有环,快慢指针相遇,快指针从链表头节点,一次走1步,慢指针继续走,快慢指针再次相遇,次节点为第一个入环节点

import java.util.*;
 
/*
public class ListNode {
    int val;
    ListNode next = null;
 
    ListNode(int val) {
        this.val = val;
    }
}*/
public class ChkLoop {
    public int chkLoop(ListNode head, int adjust) {
        // write code here
       if(head==null) return -1;
       ListNode slow=head;
       ListNode fast=head;
       while(fast!=null&& fast.next!=null){
          slow=slow.next;
          fast=fast.next.next;
          if(slow==fast){
              break;
          }
       }
       if(fast==null||fast.next==null){
           return -1;
       }
        fast=head;
        while(slow!=fast){
            slow=slow.next;
            fast=fast.next;
        }
        return slow.val;
    }
}

10无环单链表判相交

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

给定两个链表的头结点headAheadB,请返回一个bool值,代表这两个链表是否相交。保证两个链表长度小于等于500。

import java.util.*;
 
/*
public class ListNode {
    int val;
    ListNode next = null;
 
    ListNode(int val) {
        this.val = val;
    }
}*/
public class CheckIntersect {
    public boolean chkIntersect(ListNode headA, ListNode headB) {
        // write code here
        
        if (headA == null || headB == null)
            return false;
        int n = 0;
        ListNode cur1 = headA;
        while (cur1.next != null) {
            n++;
            cur1 = cur1.next;
        }
        ListNode cur2 = headB;
        while (cur2.next != null) {
            n--;
            cur2 = cur2.next;
        }
        return cur1 == cur2;
    }
         
     
}

11有环单链表判相交

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

给定两个链表的头结点head1head2(注意,另外两个参数adjust0adjust1用于调整数据,与本题求解无关)。请返回一个bool值代表它们是否相交。

import java.util.*;
 
/*
public class ListNode {
    int val;
    ListNode next = null;
 
    ListNode(int val) {
        this.val = val;
    }
}*/
public class ChkIntersection {
   public boolean chkInter(ListNode head1, ListNode head2, int adjust0, int adjust1) {
        // write code here
        ListNode loopNode1 = chkLoop(head1);
        ListNode loopNode2 = chkLoop(head2);
        //入环节点相同,(找入环节点之前相交的节点)
        if(loopNode1 == loopNode2)
            return true;
        else
        {
            ListNode cur = loopNode1.next ;
            while(cur != loopNode1)
            {
                if(cur == loopNode2)
                    return true;
                cur = cur.next;
                  
            }
            return false;
        }
    }
    //判断链表是否有环,返回有环链表的入环第一个节点
    public ListNode chkLoop(ListNode head) {
        // write code here
        if(head == null || head.next == null)
            return null;
        ListNode slow = head;
        ListNode quick = head;
        //注意判断结束条件
        while(quick != null&& quick.next != null)
        {
            slow = slow.next;
            quick = quick.next.next;
              
            if(quick == slow)
                break;
              
        }
        if(quick != slow)
            return null;
        //有环,寻找入环的第一个节点值
        quick = head;
        while(quick != slow)
        {
            quick = quick.next;
            slow = slow.next;
        }
        return quick;
    }
}

12单链表相交判断

给定两个单链表的头节点head1和head2,如何判断两个链表是否相交?相交的话返回true,不想交的话返回false。

给定两个链表的头结点head1head2(注意,另外两个参数adjust0adjust1用于调整数据,与本题求解无关)。请返回一个bool值代表它们是否相交。

import java.util.*;
 
/*
public class ListNode {
    int val;
    ListNode next = null;
 
    ListNode(int val) {
        this.val = val;
    }
}*/
public class ChkIntersection {
    public boolean chkInter(ListNode head1, ListNode head2, int adjust0, int adjust1) {
        ListNode e1 = cycleNode(head1);
        ListNode e2 = cycleNode(head2);
        if((e1 != null && e2 == null) || (e1 == null && e2 != null)) return false;
        if(e1 != null && e1 == e2) return true;
        ListNode t = e1.next;
        while(t != e1){
            if(t == e2) return true;
            t = t.next;
        }
        return false;
    }
    //获取入环节点
    private ListNode cycleNode(ListNode head){
        ListNode f = head,s = head;
        if(f.next != null){
            f = f.next.next;
            s = s.next;
        }else{
            return null;
        }
        while(f != null && f != s){
            f = f.next;
            s = s.next;
            if(f != null){
                f = f.next;
            }else{
                return null;
            }
        }
        f = head;
        while(f != s){
            f = f.next;
            s = s.next;
        }
        return f;
    }
}

 

posted @ 2017-05-08 17:35  临江仙zhe  阅读(111)  评论(0)    收藏  举报