【LeetCode刷题】链表篇

203. 移除链表元素

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode removeElements(ListNode head, int val) {
        ListNode myHead=new ListNode(0,head);
        ListNode pre=myHead;
        while(head!=null){
            if(head.val==val){
                pre.next=head.next;
                head=head.next;
            }
            else{
                pre=head;
                head=head.next;
            }
        }
        return myHead.next;
    }
}

707. 设计链表

class Node{
    public int data;
    public Node next;
    public Node(){
        ;
    }
    public Node(int val,Node next){
        this.data=val;
        this.next=next;
    }
}
class MyLinkedList {
    public int size=0;
    public Node head;

    public MyLinkedList() {
        head=new Node(0,null);
        size=0;
    }
    
    public int get(int index) {
        if(index>=size||index<0)return -1;
        Node ptr=head;
        for(int i=0;i<=index;i++){
            ptr=ptr.next;
            
        }
        return ptr.data;
        
    }
    
    public void addAtHead(int val) {
        Node newHead=new Node(val,head.next);
        head.next=newHead;
        size++;
    }
    
    public void addAtTail(int val) {
        Node ptr=head;
        while(ptr.next!=null){
            ptr=ptr.next;
        }
        Node tail=new Node(val,null);
        ptr.next=tail;
        size++;
    }
    
    public void addAtIndex(int index, int val) {
        
        Node pre=head;
        if(index==size){
            addAtTail(val);
            return ;
        }
        if(index>size)return ;
        if(index<0)index=0;

        for(int i=0;i<index;i++){
            pre=pre.next;
        }
        Node node=new Node(val,pre.next);
        pre.next=node;
        size++;
        
    }
    
    public void deleteAtIndex(int index) {
        if(index>=size)return;
        Node pre=head;
        for(int i=0;i<index;i++){
            pre=pre.next;
        }
        pre.next=pre.next.next;
        size--;
    }
}

/**
 * Your MyLinkedList object will be instantiated and called as such:
 * MyLinkedList obj = new MyLinkedList();
 * int param_1 = obj.get(index);
 * obj.addAtHead(val);
 * obj.addAtTail(val);
 * obj.addAtIndex(index,val);
 * obj.deleteAtIndex(index);
 */

206.反转链表

思路一:顺序遍历原有链表,使用头插法建立新链表即为反转后的链表。时间复杂度O(n)空间复杂度也为O(n)

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode reverseList(ListNode head) {
        ListNode newhead=new ListNode(0,null);
        ListNode ptr=newhead;
        while(head!=null){
            ptr=head;
            head=head.next;
            ptr.next=newhead.next;
            newhead.next=ptr;
        }
        
        return newhead.next;
    }
}

思路二:原地翻转,ptr用于遍历链表,pre指向在原链表中的前驱,temp用于存储ptr的后驱,最后pre所指就是反转后的头节点

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode reverseList(ListNode head) {
        ListNode pre=null;
        ListNode ptr=head;
        ListNode temp;
        while(ptr!=null){
            temp=ptr.next;
            ptr.next=pre;
            pre=ptr;
            ptr=temp;
        }
        return pre;
    }
}

24.两两交换链表的节点

思路:递归算法,首先确定出口,当链表为空或者只有一个节点时直接返回。将前两个之后的链表作为一个新链表进行递归处理,然后将前两个节点交换。

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode swapPairs(ListNode head) {
        if(head==null||head.next==null)return head;
        ListNode next=head.next;
        ListNode newNode = swapPairs(next.next);
        head.next=newNode;
        next.next=head;
        return next;
    }
}

19.删除链表的倒数第N个节点

思路:这个题的思路还是很巧妙的,利用双指针确定好距离,用距离为n的双指针同时向后遍历,当快指针指向尾节点时,slow恰好指向倒数第n个节点。

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode myHead=new ListNode(0,head);
        ListNode fast=head;
        ListNode slow=head;
        ListNode pre=myHead;
        for(int i=1;i<n;i++)fast=fast.next;
        while(fast.next!=null){
            fast=fast.next;
            slow=slow.next;
            pre=pre.next;
        }
        pre.next=slow.next;
        return myHead.next;
    }
}

面试题 02.07 . 链表相交

思路:先计算两个链表的长度,如果链表相交的话,两个链表的尾部应该是对齐的,所以我们计算出长度的差值gap,并且将长的链表的指针指向第gap个位置,这样,两个链表同时向后遍历,如果相交,肯定会同时遍历到相交的节点。

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        int len1=0,len2=0;
        ListNode ptr1=headA,ptr2=headB;
        while(ptr1!=null){
            len1++;
            ptr1=ptr1.next;
        }
        while(ptr2!=null){
            len2++;
            ptr2=ptr2.next;
        }
        ptr1=headA;
        ptr2=headB;
        if(len1<len2){
            int temp=len1;
            len1=len2;
            len2=temp;

            ptr1=headB;
            ptr2=headA;
        }
        int gap=len1-len2;
        while(gap!=0){
            ptr1=ptr1.next;
            gap--;
        }

        while(ptr1!=null){
            if(ptr1==ptr2){
                return ptr1;
            }
            ptr1=ptr1.next;
            ptr2=ptr2.next;
        }
        return null;

    }
}

142. 环形链表

思路:核心分两步,首先是判断是否存在环。我们快慢指针,fast指针一次走两步,slow指针一次走一步,如果存在环,fast和slow必然会在环内相遇。在确定环之后下一步就是找环的入口。这里需要一步数学证明推导,参考代码随想录。

/**
 * Definition for singly-linked list.
 * class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public ListNode detectCycle(ListNode head) {
        if(head==null)return head;
        ListNode fast=head,slow=head;
        while(fast!=null&&fast.next!=null){
            fast=fast.next.next;
            slow=slow.next;
            if(fast==slow){
                ListNode ptr1=head,ptr2=fast;
                while(ptr1!=ptr2){
                    ptr1=ptr1.next;
                    ptr2=ptr2.next;
                }
                return ptr1;
            }
        }
        return null;
    }
}

总结

刷完这七道链表相关的题目,比较有收获的地方有

1. 虚拟头节点。使用虚拟头节点可以使第一个结点和其他结点的操作方法一致,不用单独处理头节点

2. 对于遍历链表,如果是已知下标,用for循环会比较好。

3. 对于插入和删除操作,需要先找到前驱节点

4. 双指针的应用非常巧妙,可以实现一次遍历解决问题

5. 相交链表和环形链表需要加强记忆

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值