算法学习———链表(Java版)

 leetcode本周刷题路线:

 203. 移除链表元素(简单):

        题目描述:

        给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.value  ==  val的节点,并返回新的头节点。

        示例:

 

        解题思路:

        设置两个指针 pre 和 cur ,其中 cur 指针用于检测当前节点的值是否与 val相等,若相等则通过 pre 指针将 cur 所在的节点删除 。在链表的 head 前添加一个值为 -1的节点并将原来的 head 指向新添加的节点处, pre 指向 head 处,cur 指向 pre.next 处。pre 与 cur 同时开始遍历链表直至 cur == NULL ,遍历完成则程序运行结束。

        删除节点的步骤:

                pre.next = cur.next;

                cur = cur.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 removeElements(ListNode head, int val) {
        ListNode cur, pre;
        head = new ListNode(-1, head);
        pre = head;
        cur = pre.next;
        while(cur != null){
            if(cur.val == val){
                pre.next = cur.next;
                cur = cur.next;
                continue;
            }
            pre = pre.next;
            cur = pre.next;
        }
        return head.next;
    }
}


206. 反转链表(简单):

        题目描述:

        给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

        示例:

        解题思路:头插法反转链表

        新建一个链表头节点 newhead 、指针 p 和 temp ,其中 p 指针指向 head,temp 指针用于保存 p 所在节点的下一节点的地址。p 指针从 head 处遍历链表,指针 p 指向某一结点,就将该节点添加至newhead后方。当 p == null 时,程序运行结束。

        头插法的步骤:

                p.next = newhead.next;

                newhead.next = p;

        解题代码:

/**
 * 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(), p, temp;
        p = head;
        while(p != null){
            temp = p.next;
            p.next = newhead.next;
            newhead.next = p;
            p = temp;
        }
        return newhead.next;
    }
}


 24.两两交换链表中的节点(中等):

        题目描述:

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

        示例:

        

        解题思路: 

        设置三个指针 pre、p、q ,pre 指向一个为设置值的节点且 pre.next = head,指针 p、q、head 同时指向指针 pre 所指处。将指针 p、q 两两指向链表中相邻节点( p 在 q前),交换指针p、q 所在位置节点的位置后,通过指针 pre 将交换节点后的部分连接起来。

        指针 p、 q 所指节点交换并与链表链接步骤:

                p.next = q.next;

                q.next = p;

                pre.next = q;

        解题代码:

/**
 * 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 pre = new ListNode(), p, q;
        System.out.print(pre.val);
        pre.next = head;
        p = q = head = pre;
        while(p.next != null){
            p = pre.next;
            q = p.next;
            if(q == null)
                break;
            p.next = q.next;
            q.next = p;
            pre.next = q;
            pre = p;
        }
        return head.next;
    }
}


19. 删除链表的倒数第N个结点(中等):

        题目描述:

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

        示例:

        

        解题思路:双指针法

        在链表表头前添加一个值域为 -1 的节点,将原来指向链表头部的指针 head 指向新添加的节点,设置指针 p1、p2并指向指针 head 所指节点处。先让指针 p1 移动 n 步后,再让指针 p1、p2同时向后移动,此时指针 p1 与 指针 p2 的距离固定为 n,每次移动距离均为1,当指针 p1 移动到链表最后一个节点时,p2当前位置即为所要删除位置节点的前一个节点(也即链表倒数第 n 个节点),执行 p2.next = p2.next.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 removeNthFromEnd(ListNode head, int n) {
        ListNode p1, p2;
        head = new ListNode(-1, head);
        p1 = p2 = head;
        while(n-- != 0)
            p1 = p1.next;
        while(p1.next != null){
            p1 = p1.next;
            p2 = p2.next;
        }
        p2.next = p2.next.next;
        return head.next;
    }
}


160. 相交链表(简单):

        题目描述:

        给你两个单链表的头节点 headA 和 headB,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null    

        示例:

        解题思路:

        设置两个指针 p1, p2,分别指向 headA,headB,当指针 p1、p2 遍历完当前链表后,交换两个指针所指的链表,并从其头节点重新遍历,消除指针 p1、p2 移动的距离差使指针 p1、p2 在第二次经过两链表交点时走过的距离相等。

        解题代码:

/**
 * 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) {
        if(headA == null || headB == null)
            return null;
        ListNode p1, p2;
        p1 = headA; 
        p2 = headB;
        while(p1 != p2){
            p1 = p1 == null ? headB : p1.next;
            p2 = p2 == null ? headA : p2.next;
        }
        return p1;
    }
}


142.环形链表 II(中等):

        题目描述:

        给定一个链表的头节点 head,返回链表开始入环的第一个节点。如果链表无环,则返回null

        示例:

        

 

        解题思路:快慢指针

        设置两个指针,分别为 fast 和 slow,指针 fast 一次移动两步,指针 slow 一次移动一步,若该指针 fast 最终会指向 null ,则该链表无环;若该链表有环则指针 fast 和指针 slow 必定会在环内相遇且指针 fast 已在环内循环了至少一次,此时指针 fast 移动的距离是指针 slow 移动距离的两倍。

        设链表表头到入环点的距离为 a,入环点到快慢指针相遇点的距离为 b,快慢指针相遇点到下一次入环点的距离为 c。可得:指针 fast 移动的距离为 a + b + c + b, 指针 slow 移动的距离为 a + b。又因为指针 fast 移动的距离是指针 slow 的两倍,故可列出等式 a + b + c + b = 2(a + b),易得 a = c,即,此时再设置一个指针 temp 从链表表头和指针 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 null; 
        ListNode slow = head, fast = head;
        boolean hasCycle = false;
        while (fast.next != null && fast.next.next != null) {
            slow = slow.next;
            fast = fast.next.next;
            if (slow == fast) {
                hasCycle = true;
                break;
            }
        }
        if (hasCycle) {
            ListNode temp = head;
            while (slow != temp) {
                slow = slow.next;
                temp = temp.next;
            }
            return temp;
        } 
        else 
            return null;
    }
}

学习小结:

        链表是比较常见的数据结构之一,也是一些更高级的数据结构的基础。熟练掌握链表对于往后算法和数据结构的学习至关重要,同时,与链表相关的操作必定离不开指针,因此熟悉指针的原理和作用也同样重要。在本周对于链表的学习中学习到了许多只针对操作方法,例如 ” 双指针 “、” 快慢指针 “等,其中 ” 快慢指针 ‘ 这一操作十分的巧妙,让我印象深刻,让我对链表和指针都有了更深层次的理。“ 环形链表 II ” 这道题是我做的第一道通过数学思想来理解的算法题,其中就用到了 ” 快慢指针 “ ,为了理解这道题还是花了点时间的,虽然很难很费脑子,但理解这道题的一瞬间的成就感和满足感是无与伦比的,这就是算法的乐趣吧!

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值