代码随想录算法训练营第四天 | Java | 24. 两两交换链表中的节点,19.删除链表的倒数第N个节点 ,面试题 02.07. 链表相交 ,142.环形链表II

写在前面:这几个题确实好题,双指针大法好(快指针慢指针),值得反复思考。

24. 两两交换链表中的节点

题目: 给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。

提示:

  • 链表中节点的数目在范围 [0, 100] 内
  • 0 <= Node.val <= 100

思路: 首先结点顺序交换,考虑用双指针记录交换结点和后续结点起始位置。其次返回链表表头,考虑使用虚拟头结点。

注意:双结点使用时一个记录当前交换对的第一个结点,另一个记录下组交换对结点的位置。

Java实现

/**
 * 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) {
        // 设置虚拟头结点
        ListNode dummyHead = new ListNode(0);
        dummyHead.next = head;
        ListNode cur = dummyHead;
        ListNode temp,temp1;
        while(cur.next!=null && cur.next.next!= null){  // 保证至少有两个节点用来交换
            temp = cur.next;    // 保存两个节点中的第一个节点
            temp1 =cur.next.next.next;      // 保存交换位置后的起始位置的新节点
            cur.next = temp.next;
            cur.next.next = temp;
            cur.next.next.next = temp1;
            cur = cur.next.next;
        }
        return dummyHead.next;
    }
}

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

题目: 给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。

提示:

  • 链表中结点的数目为 sz
  • 1 <= sz <= 30
  • 0 <= Node.val <= 100
  • 1 <= n <= sz

思路:删除倒数第n个结点,最直接的方法是遍历表长后再确定删除结点位置。还可以采用双指针法,一个指针定位链表尾部,另一个指针定位删除结点前一位,两个指针间隔n。

注意:链表尾部指针先走n位,然后定位指针和链表指针同步行进。 

Java实现

/**
 * 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 dummyHead = new ListNode(0);
        dummyHead.next = head;
        ListNode sign = dummyHead;   // 被删除节点前一位
        ListNode temp = dummyHead;   // 查找链表结尾
        // 删除倒数第n个节点,向前预留n+1位节点
        for(int i =0;i<=n;i++){
            temp = temp.next;
        }
        // temp只判断当前指向状态
        while(temp!= null){
            temp = temp.next;
            sign = sign.next;
        }
        sign.next = sign.next.next;
        return dummyHead.next;        
    }
}

 3 面试题 02.07. 链表相交

题目: 给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null 。图示两个链表在节点 c1 开始相交

题目数据 保证 整个链式结构中不存在环。注意,函数返回结果后,链表必须 保持其原始结构 。

提示:

  • listA 中节点数目为 m
  • listB 中节点数目为 n
  • 0 <= m, n <= 3 * 104
  • 1 <= Node.val <= 105
  • 0 <= skipA <= m
  • 0 <= skipB <= n
  • 如果 listA 和 listB 没有交点,intersectVal 为 0
  • 如果 listA 和 listB 有交点,intersectVal == listA[skipA + 1] == listB[skipB + 1]

思路:两个链表可以相交,相交结点一致,相交部分长度一致,因此链表长度不同时一定是以短链表长度为比较起点。然后,逐个比较结点是否一致即可。

注意:相交部分是同一结点,因此地址是一致的,比较时注意不要单纯以结点值为评判标准。

Java实现

/**
 * 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 la=0,lb=0;
        ListNode dummyHeadA  = headA;
        ListNode dummyHeadB = headB;
        while(dummyHeadA!= null){
            la++;
            dummyHeadA = dummyHeadA.next;
        }
        while(dummyHeadB!=null){
            lb++;
            dummyHeadB = dummyHeadB.next;
        }

        // 表头复原
        dummyHeadA = headA;
        dummyHeadB = headB;

        // 根据la、lb长度分情况判断,为简化计算可将A设置为长链,B为短链
        if(la<lb){
            int t =lb;
            lb = la;
            la = t;
            ListNode temp = dummyHeadA;
            dummyHeadA = dummyHeadB;
            dummyHeadB = temp;
        }
        for(int i=0;i<la-lb;i++){
            dummyHeadA = dummyHeadA.next;
        }
        while(dummyHeadA!=null){
            if(dummyHeadA == dummyHeadB){
                return dummyHeadA;
            }
            dummyHeadA = dummyHeadA.next;
            dummyHeadB = dummyHeadB.next;
        }
        return null;
    }
}

142. 环形链表 II

题目:给定一个链表的头节点  head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。不允许修改 链表。

提示:

  • 链表中节点的数目范围在范围 [0, 104] 内
  • -105 <= Node.val <= 105
  • pos 的值为 -1 或者链表中的一个有效索引

思路:首先,确定是否有环;其次,确定入口位置。确实难,目前还描述不清楚,推荐直接看解析 环形链表

注意:确定环入口的数学问题要想清楚。

Java实现

/**
 * 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) {
        ListNode fast = head;
        ListNode slow = head;
        // 判断是否有环
        while(fast!=null && fast.next!=null){
            fast = fast.next.next;
            slow = slow.next;
            if (fast==slow){    //判断有环
                ListNode index1 = fast;
                ListNode index2 = head;
                while(index1!=index2){
                    index1 = index1.next;
                    index2 = index2.next;
                }
                return index1;
            }
        }
        return null;
    }
}

  • 12
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值