LC01:链表合集

本专栏后续记录自己刷题遇到的链表相关的题目

82. 删除排序链表中的重复元素 II

题目链接:82. 删除排序链表中的重复元素 II
在这里插入图片描述
在这里插入图片描述
时隔多月再次刷到熟悉的题目,第一次看到题目,将其做成了对于重复的元素只保留其中一个,对于这种思路实现:

  • 构建一个返回链表ans,同时创建创建链表cur = head,遍历cur,如果cur.val != ans.val,说明此时遇到新出现的元素,将cur接在ans后面,继续遍历。如果cur.val == ans.val,说明当前cur和ans中是重复元素,直接跳过。

简易代码:

/**
 * 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 deleteDuplicates(ListNode head) {
        ListNode ans = new ListNode(-200);
        ListNode root = ans, slow = head, fast = head;
        while(fast != null){
            if(slow.val != fast.val){
                if(slow.next == fast){
                    root.next = slow;
                    root = root.next;
                }
                slow = fast;
            }
            fast = fast.next;
        }
        root.next = slow.next == null ? slow : null;
        return ans.next;
    }
}

后续没有通过,再次看题目,理解错了。随后想了一种使用快慢指针的做法,定义满指针slow和快指针fast,如果fast.val == slow.val,直接fast.next = fast(后移fast指针)。随后判断[slow, fast]之间的元素个数,如果元素个数大于1,说明是重复的,此时直接令slow = fast.next同时fast = fast.next跳过当前区间的所有元素,只有区间元素个数为1时才将slow接在ans的后面。
但是遇到一个问题,此题对应的是链表,不能直接计算[slow, fast]之间的元素个数,随后又想到,直接判断slow.next == fast,如果 成立,那么说明[slow, fast]区间的元素个数为1,此时可以将slow接在ans后面,否则不能。同时需要考虑当fast 遍历到链表末尾时,slow是否是倒数第一个元素,如果是,此时也可以接上,如果不是,说明存在重复元素,舍弃。
最终代码实现:

/**
 * 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 deleteDuplicates(ListNode head) {
        if(head == null){
            return head;
        }
        ListNode ans = new ListNode(-200);
        ListNode root = ans, slow = head, fast = head;
        while(fast != null){
            if(slow.val != fast.val){
                if(slow.next == fast){
                    root.next = slow;
                    root = root.next;
                }
                slow = fast;
            }
            fast = fast.next;
        }
        root.next = slow.next == null ? slow : null;
        return ans.next;
    }
}

完成之后看到之前写的代码,如下,我这次想的方法和之前相比非常简单。

/**
 * 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 deleteDuplicates(ListNode head) {
        ListNode dump = new ListNode(0, head);
        if(head == null || head.next == null)   return head;    
        ListNode cur = dump, slow = head, fast = head.next;
        while(fast != null){
            if(fast.val == slow.val){
                while(fast != null && fast.val == slow.val){
                    fast = fast.next;
                }
                // cur.next = fast;
                // cur = fast;
                slow = fast;
                if(fast != null)    fast = fast.next;
            }else{
                cur.next = slow;
                cur = slow;
                slow = fast;
                fast = fast.next;
            }
        }
        cur.next = slow;
        //if(slow != null) slow.next = null;
        return dump.next;
    }
}

92. 反转链表 II

题目链接:92. 反转链表 II
在这里插入图片描述
这个题目之前也做过,但前面做时候使用的方法是,找到[left-right]区间的链表,随后对区间进行反转,反转后再将其接起来。
这一次我直接按照进阶要求来做,只使用一次遍历。由于需要反转[left, right]区间的链表,明显一趟遍历完成需要保存的节点状态包括,leftNode,left的前一个节点,right节点,right节点的后一个节点,以及在left以及right区间进行反转时的链表头节点。总共5个节点。
注意保存left的前一个节点的做法:我下面的代码使用的是标志位判断,除了标志位判断,直接使用cnt < left也可以。
代码实现:

/**
 * 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 reverseBetween(ListNode head, int left, int right) {
        if(head == null || left == right){
            return head;
        }
        ListNode dump = new ListNode(0, head);
        ListNode prev = dump, cur = head, leftNode = null, rightNode = null, rightNextNode = null, subCur = null;
        int cnt = 0, flag = 1;
        while(cur != null){
            ListNode curNext = cur.next;
            ++cnt;
            if(cnt >= left && cnt <= right){
                if(cnt == left){
                    leftNode = cur;
                }else if(cnt == right){
                    rightNode = cur;
                    rightNextNode = cur.next;
                }
                // left-right区间的链表反转操作
                cur.next = subCur;
                subCur = cur;
                flag = -1;
            }else if(flag == 1){
                // flag标志作用,确保prev保存的值只是left的前一个节点,避免保存到right后续节点
                prev = cur;
            }
            cur = curNext;
        }
        prev.next = rightNode;
        leftNode.next = rightNextNode;
        return dump.next;
    }
}

// 不使用标志位版本
/**
 * 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 reverseBetween(ListNode head, int left, int right) {
        if(head == null || left == right){
            return head;
        }
        ListNode dump = new ListNode(0, head);
        ListNode prev = dump, cur = head, leftNode = null, rightNode = null, rightNextNode = null, subCur = null;
        int cnt = 0;
        while(cur != null){
            ListNode curNext = cur.next;
            ++cnt;
            if(cnt >= left && cnt <= right){
                if(cnt == left){
                    leftNode = cur;
                }else if(cnt == right){
                    rightNode = cur;
                    rightNextNode = cur.next;
                }
                // left-right区间的链表反转操作
                cur.next = subCur;
                subCur = cur;
            }
            if(cnt < left){
                prev = cur;
            }
            cur = curNext;
        }
        prev.next = rightNode;
        leftNode.next = rightNextNode;
        return dump.next;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值