LeetCode:链表总结

反转链表

1.1 从前往后遍历

public ListNode reverseList(ListNode head) {
    ListNode cur = head;
    ListNode next = null;
    ListNode pre = null;
    while(cur!=null){
        //cur不为空才求它的next
        next = cur.next;
        cur.next = pre;
        pre = cur;
        cur = next;
    }
    //返回时候cur为null,表头为pre
    return pre;
}

1.2 递归

public ListNode reverseList(ListNode head) {
    if(head==null||head.next==null)
        return head;
    //保存新的头节点
    ListNode newHead = reverseList(head.next);
    //后面的节点的next等于当前的节点
    head.next.next = head;
    //当前节点的next等于null,和上一步的这两步的操作并没有影响前一个节点的next指向当前head
    head.next = null;
    return newHead;
}

1.3 从尾到头输出链表

剑指offer06:输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回)。

class Solution {
    public ListNode reverseList(ListNode head) {
        if(head==null||head.next==null){
            return head;
        }
        ListNode newhead = reverseList(head.next);
        head.next.next = head;
        head.next = null;
        return newhead;
    }
}

1.3 两两交换节点

public ListNode swapPairs(ListNode head) {
    if(head==null||head.next==null)
        return head;
    //保存后面的结果
    ListNode back = swapPairs(head.next.next);
    //交换当前这两个
    ListNode next = head.next;
    head.next = back;
    next.next =head;
    //返回新的头
    return next;
}

1.3 K个一组反转链表

递归方法:和上一题类似

class Solution {
    public ListNode reverseKGroup(ListNode head, int k) {
        ListNode tail = head;
        int count = k-1;
        while(count>0&&tail!=null){
            tail = tail.next;
            count--;
        }
        //找到第K个元素,不足K个返回头节点,不用翻转
        if(tail==null)
            return head;
        //下一组的开头
        ListNode back = tail.next;
        //递归反转后面
        ListNode backhead = reverseKGroup(back,k);
        //当前这K个元素一组进行翻转,从head到tail,断开tail后面
        tail.next = null;
        ListNode newhead = reverse(head);
        //head成为了尾巴
        head.next = backhead;
        return newhead;

    }


    public ListNode reverse(ListNode head){
        if(head==null||head.next==null)
            return head;
        ListNode back = head.next;
        ListNode newhead = reverse(back);
        back.next = head;
        head.next = null;
        return newhead;
    }
}

遍历方法: 

class Solution {
    public ListNode reverseKGroup(ListNode head, int k) {
        ListNode dummy = new ListNode();
        dummy.next = head;
        ListNode pre = dummy;
        ListNode tail = dummy;
        int count = 0;
        while(true){
            count =0;
            //找到第k个节点,作为结尾
            while(tail!=null&&count<k){
                tail=tail.next;
                count++;
            }
            if(tail==null)
                break;
            //这一轮反转后,变成结尾的节点,本来是第一个 将要成为最后一个,也就是下一轮的开头前一个
            ListNode nexthead = pre.next;
            //尾巴还没成为第一个的时候
            while (pre.next != tail) {
                //要插入到尾巴的节点
                ListNode cur = pre.next;
                pre.next = pre.next.next;
                cur.next = tail.next;
                tail.next = cur;

            }
            //结尾成为下一轮的开始
            pre = nexthead;
            tail = nexthead;        
        }
        return dummy.next;
    }
}

奇偶链表

328:给定一个单链表,把所有的奇数节点和偶数节点分别排在一起。请注意,这里的奇数节点和偶数节点指的是节点编号的奇偶性,而不是节点的值的奇偶性。

输入: 1->2->3->4->5->NULL

输出: 1->3->5->2->4->NULL

public ListNode oddEvenList(ListNode head) {
    if(head==null||head.next==null)
        return head;
    ListNode oddhead = head;
    ListNode evenhead = head.next;
    ListNode oddcur = head;
    ListNode evencur = evenhead;
    //这个条件使evencur一定能跳到下一个偶数节点
    //evencur一直到倒数一个非空或者空才停止(由链表总个奇偶决定),因为这个条件
    while(evencur!=null&&evencur.next!=null){
        //奇数的next等于偶数的next
        oddcur.next=evencur.next;
        //奇数的遍历节点往下跳,跳到下一个奇数
        oddcur = oddcur.next;
        //偶数的next等于奇数的next
        evencur.next =oddcur.next;
        evencur = evencur.next;
    }
    //偶数节点的最后一个都是null,奇数不是
    oddcur.next = evenhead;
    return oddhead;

}

链表中间节点

    public ListNode findMid(ListNode l1){
        ListNode dummy = new ListNode();
        dummy.next = l1;
        ListNode fast=dummy,slow =dummy;
        while(fast!=null&&fast.next!=null){
            fast = fast.next.next;
            slow = slow.next;
        }
        //如果是奇数个,找的是中间节点,如果是偶数个,找的是前半部分的最后一个节点
        return slow;
    }

合并有序链表

4.1 合并两个有序链表

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

4.2 合并K个有序链表

先划分,再合并

class Solution {
    public ListNode mergeKLists(ListNode[] lists) {
        return merge(lists,0,lists.length-1);
    }
    //归并
    public ListNode merge(ListNode[] lists,int low ,int high){
        if(low==high)
            return lists[low];
        if(low>high)
            return null;
        int mid = (low+high)/2;
        //再划分左右两部分
        ListNode left = merge(lists,low,mid);
        ListNode right = merge(lists,mid+1,high);
        //合并左右两部分
        return mergeTwoList(left,right);
    }

    //合并两个链表
    public ListNode mergeTwoList(ListNode head1,ListNode head2){
        ListNode dummy = new ListNode();
        ListNode cur = dummy;
        while(head1!=null&&head2!=null){
            if(head1.val<head2.val){
                cur.next =head1;
                head1 = head1.next;
            }             
            else{
                cur.next = head2;
                head2 = head2.next;
            }
            cur = cur.next;
        }
        cur.next = head1==null?head2:head1;
        return dummy.next;
    }

}

删除链表重复元素

5.1 保留

class Solution {
    public ListNode deleteDuplicates(ListNode head) {
        if(head==null||head.next==null)
            return head;
        ListNode cur = head;
        while(cur!=null){
            ListNode next = cur.next;
            while(next!=null&&next.val == cur.val){
                cur.next = next.next;
                next = cur.next;
            }
            cur = cur.next;
        }
        return head;
    }
}

5.2 不保留

public ListNode deleteDuplicates(ListNode head) {
    if(head==null||head.next==null)
        return head;
    ListNode dummy = new ListNode();
    dummy.next = head;
    ListNode pre =dummy,cur=head,next = head;
    while(cur!=null){
        next = cur.next;
        if(next!=null&&cur.val==next.val){
            while(next!=null&&cur.val==next.val){
                next=next.next;
            }
            pre.next = next;
        }else{
            pre=pre.next;
        }
        cur = next;
    }
    return dummy.next;
}

链表排序

6.1 升序排序

148:升序排序链表,找中点+归并

class Solution {
    public ListNode sortList(ListNode head) {
        if(head==null||head.next==null)
            return head;
        ListNode midnode = findMid(head);
        ListNode right = midnode.next;
        midnode.next=null;
        //先划分完左右,再合并
        return merge(sortList(head),sortList(right));
    }
    public ListNode findMid(ListNode l1){
        ListNode dummy = new ListNode();
        dummy.next = l1;
        ListNode fast=dummy,slow =dummy;
        while(fast!=null&&fast.next!=null){
            fast = fast.next.next;
            slow = slow.next;
        }
        return slow;
    }
    public ListNode merge(ListNode l1,ListNode l2){
        ListNode dummy= new ListNode();
        ListNode cur =dummy;
        while(l1!=null&&l2!=null){
            if(l1.val<l2.val){
                cur.next = l1;
                l1=l1.next;
            }else{
                cur.next = l2;
                l2 = l2.next;
            }
            cur = cur.next;
        }
        cur.next = l1==null?l2:l1;
        return dummy.next;
    }
}

6.2 重排序链表

143:重排序链表,后半部分链表倒序之后,间隔插入到前半部

给定一个单链表 L 的头节点 head

单链表 L 表示为: L0 → L1 → … → Ln - 1 → Ln

请将其重新排列后变为: L0 → Ln → L1 → Ln - 1 → L2 → Ln - 2 → …

class Solution {
    public void reorderList(ListNode head) {
        ListNode mid = findMidNode(head);
        ListNode right = mid.next;
        mid.next = null;
        right = reverse(right);
        ListNode p = head;
        ListNode q = right;
        while(q!=null){
            ListNode next = q.next;
            q.next = p.next;
            p.next = q;
            p = p.next.next;
            q = next;
        }
        return ;
    }
    public ListNode findMidNode(ListNode head){
        ListNode dummy = new ListNode();
        dummy.next = head;
        ListNode fast = dummy;
        ListNode slow = dummy;
        while(fast!=null&&fast.next!=null){
            fast = fast.next.next;
            slow = slow.next;
        }
        return slow;
    }
    public ListNode reverse(ListNode head){
        if(head==null||head.next==null)
            return head;
        ListNode pre = null;
        ListNode cur = head;
        ListNode next = cur.next;
        while(cur!=null){
            next = cur.next;
            cur.next = pre;
            pre = cur;
            cur =next;
        }
        return pre;
    }
}

6.3 排序奇升偶降链表

给定一个奇数位升序,偶数位降序的链表,将其重新排序。

输入: 1->8->3->6->5->4->7->2->NULL

输出: 1->2->3->4->5->6->7->8->NULL

public class LinkedListTest {
    //返回分隔开的奇偶
    public ListNode[] oddEvenList(ListNode head){
        ListNode oddhead = head;
        ListNode evenhead = head.next;
        ListNode oddcur = oddhead;
        ListNode evencur = evenhead;
        //保证奇数有下一个,并且偶数有下一个,保证了偶数链表最后一定是null,但奇数就不一定的
        while(evencur!=null&&evencur.next!=null){
            oddcur.next = evencur.next;
            oddcur = oddcur.next;
            evencur.next = oddcur.next;
            evencur =evencur.next;
        }
        //注意断开奇数的结尾,否则形成环
        oddcur.next = null;
        return new ListNode[]{oddhead,evenhead};
    }
    //反转偶数部分
    public ListNode reverse(ListNode head){
        if(head.next==null)
            return head;
        ListNode next = head.next;
        ListNode newhead = reverse(next);
        next.next=head;
        head.next =null;
        return newhead;
    }
    //合并奇偶
    public ListNode mergeList(ListNode l1,ListNode l2){
        ListNode dummy = new ListNode();
        ListNode cur =dummy;
        while(l1!=null&&l2!=null){
            if(l1.val<=l2.val){
                cur.next =l1;
                l1 =l1.next;
            }else {
                cur.next =l2;
                l2 =l2.next;
            }
            cur = cur.next;
        }
        cur.next = l1==null?l2:l1;
        return dummy.next;
    }

    public ListNode sortOddEvenList(ListNode head){
        if(head==null||head.next==null)
            return head;
        ListNode[] oddeven = oddEvenList(head);
        ListNode oddhead =oddeven[0];
        ListNode evenhead = oddeven[1];
        evenhead = reverse(evenhead);
        return mergeList(oddhead, evenhead);
    }
}

回文链表

先存入数组,在判断是否回文

public boolean isPalindrome(ListNode head) {
    ArrayList<Integer> result = new ArrayList<>();
    while(head!=null){
        result.add(head.val);
        head = head.next;
    }
    int length = result.size();
    for(int i=0;i<length/2;i++){
        if(result.get(i)!=result.get(length-1-i))
            return false;
    }
    return true;
}

复制带随即指针的链表

构建源节点和新节点的哈希映射

class Solution {
    public Node copyRandomList(Node head) {
        HashMap<Node,Node> map = new HashMap<>();
        Node dummy = new Node(0);
        Node newcur = dummy;
        Node oldcur = head;
        while(oldcur!=null){
            int val = oldcur.val;
            newcur.next = new Node(val);
            map.put(oldcur,newcur.next);
            oldcur=oldcur.next;
            newcur =newcur.next;
        }
        oldcur = head;
        newcur = dummy.next;
        while(oldcur!=null){
            //当前节点的随机指针
            Node random = map.get(oldcur.random);
            if(random!=null){
                newcur.random = random;
            }
            oldcur = oldcur.next;
            newcur = newcur.next;
        }
        return dummy.next;
    }
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值