链表(一)

从尾到头打印链表

翻转链表

翻转链表II

链表划分

合并两个排序链表

合并k个排序链表

链表求和

带环链表

找出带环链表的环入口

 

 

 从尾到头打印链表

输入一个链表,从尾到头打印链表每个节点的值。

public class Solution {
    // 递归实现
    ArrayList<Integer> result = new ArrayList<>();
    public ArrayList<Integer> printListFromTailToHead(ListNode listNode){
        if(listNode != null){
            this.printListFromTailToHead(listNode.next);
            result.add(listNode.val);
        }
        return result;
    }
    
    // 借用stack
    public ArrayList<Integer> printListFromTailToHead3(ListNode listNode) {
        Stack<Integer> stack = new Stack<>();
        ArrayList<Integer> list = new ArrayList<>();
        while(listNode!=null){
            stack.push(listNode.val);
            listNode = listNode.next;
        }
        while(!stack.isEmpty()){
            list.add(stack.pop());
        }
        return list;
    }
}

 

 

翻转链表

// 从头到尾遍历原链表,每遍历一个节点,将其摘下放在新链表的最前段, O(n)
public ListNode reverse(ListNode head) {
    ListNode prev = null;
    ListNode cur = head;
    
    while (cur != null) {
        ListNode temp = cur; // 保存当前要处理的节点
        cur = cur.next;     // 跳到下一个节点
        temp.next = prev;
        prev = temp;
    }
    return prev;
}

// 递归
public ListNode reverse2(ListNode head) {
    if (head == null || head.next == null) {
        return head;
    }
    
    ListNode reHead = reverse2(head.next);
    head.next.next = head;
    head.next = null;
    return reHead;
}

 

 翻转链表II

翻转链表中第m个节点到第n个节点的部分。(给出链表1->2->3->4->5->null, m = 2 和n = 4,返回1->4->3->2->5->null

分析:对于m、n,确定要翻转2->3->4。先找到2的前一个节点,prev;按照普通翻转链表的做法,翻转n-m次;最后,node[m].next=node[n].next,prev.next=node[n]

 

public ListNode reverseBetween(ListNode head, int m , int n) {
    if(head==null || head.next==null || m==n){
        return head;
    }
    
    ListNode pre;
    ListNode dummy = new ListNode(0);
    pre = dummy;
    dummy.next = head;
    
    for(int i=0; i<m-1; i++){
        pre = pre.next;
    }
    
    ListNode cur = pre.next, p = pre.next, node = null;
    for(int i=0; i<=n-m; i++){
        ListNode nxt = cur.next;
        cur.next =node;
        node=cur;
        cur = nxt;
    }
    
    p.next = cur;
    pre.next = node;
    return dummy.next;
}

 

 链表划分

给定一个单链表和数值x,划分链表使得所有小于x的节点排在大于等于x的节点之前。 保留两部分内链表节点原有的相对顺序。

( 链表 1->4->3->2->5->2->null,并且 x=3 返回 1->2->2->4->3->5->null )

public ListNode partition(ListNode head, int x) {
    ListNode leftDummy = new ListNode(0);
    ListNode rightDummy = new ListNode(0);
    ListNode left = leftDummy, right = rightDummy;
    // 两个指针,left保存小于x的节点,right保存大于x的节点,最后left.next=rightDummy.next
    while (head != null) {
        if (head.val < x) {
            left.next = head;
            left = head;
        } else {
            right.next = head;
            right = head;
        }
        head = head.next;
    }

    right.next = null;
    left.next = rightDummy.next;
    return leftDummy.next;
}

 

合并两个排序链表

将两个排序链表合并为一个新的排序链表

(给出 1->3->8->11->15->null2->null, 返回 1->2->3->8->11->15->null。)

public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
    ListNode dummy = new ListNode(0);
    ListNode lastNode = dummy;
    
    while(l1!=null && l2!=null){
        if(l1.val<l2.val){
            lastNode.next = l1;
            l1 = l1.next;
        }else{
            lastNode.next = l2;
            l2 = l2.next;
        }
        
        lastNode = lastNode.next;
    }
    
    if(l1!=null){
        lastNode.next = l1;
    }else{
        lastNode.next = l2;
    }
    
    return dummy.next;
}

 

 合并k个排序链表

public ListNode mergeKLists(ListNode[] lists) {
    if(lists==null || lists.length==0)  return null;
    
    mergeKLists(lists, 0, lists.length-1);
    return lists[0];
}

public void mergeKLists(ListNode[] lists, int left, int right){
    if(left>=right)  return;
    
    int mid = left + (right+1-left)/2;
    mergeKLists(lists, left, mid-1);
    mergeKLists(lists, mid, right);
    
    ListNode dummy = new ListNode(0);
    merge2Lists(lists[left], lists[mid], dummy);
    lists[left] = dummy.next;
}


public void merge2Lists(ListNode l1, ListNode l2, ListNode dummy){
    if(l1==null && l2==null){
        return;
    }
    if(l1==null || (l2!=null && l2.val< l1.val)){
        dummy.next = l2;
        merge2Lists(l1, l2.next, dummy.next);
    }else if(l2==null || (l1!=null && l1.val<= l2.val)){
        dummy.next = l1;
        merge2Lists(l1.next, l2, dummy.next);
    }
}

 

链表求和

两个用链表代表的整数,其中每个节点包含一个数字。数字存储按照在原来整数中相反的顺序,使得第一个数字位于链表的开头。写出一个函数将两个整数相加,用链表形式返回和。

( 给出两个链表(2 -> 4 -> 3) + (5 -> 6 -> 4),返回7 -> 0 -> 8 )

public ListNode addLists(ListNode l1, ListNode l2) {
    if(l1 == null && l2 == null) {
        return null;
    }
        
    ListNode head = new ListNode(0);
    ListNode point = head;
    int carry = 0;    // 进位
    
    while(l1 != null && l2!=null){
        int sum = carry + l1.val + l2.val;
        point.next = new ListNode(sum % 10);    //本位上的数
        carry = sum / 10;    // 进位
        l1 = l1.next;
        l2 = l2.next;
        point = point.next;
    }
    
    while(l1 != null) {
        int sum =  carry + l1.val;
        point.next = new ListNode(sum % 10);
        carry = sum /10;
        l1 = l1.next;
        point = point.next;
    }
    
    while(l2 != null) {
        int sum =  carry + l2.val;
        point.next = new ListNode(sum % 10);
        carry = sum /10;
        l2 = l2.next;
        point = point.next;
    }
    
    if (carry != 0) {
        point.next = new ListNode(carry);
    }
    return head.next;
}

 

带环链表

判断链表是否有环

public boolean hasCycle(ListNode head) {
    if(head==null || head.next==null){
        return false;
    }
    
    ListNode slow = head;
    ListNode fast = head;
    while(fast!=null && fast.next!=null){
        slow = slow.next;
        fast = fast.next.next;
        if(slow == fast){
            return true;
        }
    }
    return false;
}

 

找出带环链表的环入口

给定一个链表,如果链表中存在环,则返回到链表中环的起始节点的值,如果没有环,返回null。

public ListNode detectCycle(ListNode head) {
    if(head==null || head.next==null || head.next.next==null)  
        return null;
        
    ListNode pointer1 = head.next;
    ListNode pointer2 = head.next.next;
    
    //Step 1
    while(pointer1!=pointer2){
        if(pointer2.next==null || pointer2.next.next==null)   
            return null;
        pointer1 = pointer1.next;
        pointer2 = pointer2.next.next;
    }
    pointer1 = head;
    
    //Step 2  p1从head开始,p2从交汇处开始,二者同时到达的位置就是环入口
    while(pointer1!=pointer2){
        pointer1 = pointer1.next;
        pointer2 = pointer2.next;
    }
    return pointer1;
}

 

posted @ 2016-06-15 12:21  Hesier  阅读(182)  评论(0编辑  收藏  举报