双指针解决LeetCode链表

链表操作一般小trike设置一个空的节点指向头,以防止后续出现null的问题

21. 合并两个有序链表

解法:

双指针,一个指针指向A,一个指针指向B比较两指针哪个val小,就先让新链表的头指向该指针的值

代码:

class Solution {
    public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
        if(list1==null && list2==null){ // 都为空,则返回null
            return null;
        }
        if(list1==null){ // 其中一个为空,则返回另一个
            return list2;
        }
        if(list2==null){
            return list1;
        }

        ListNode dummyNode = new ListNode(0);
        ListNode d = dummyNode;
        ListNode l1 = list1;
        ListNode l2 = list2;

        while(l1!=null && l2!=null){
            if(l1.val<=l2.val){
                d.next = l1;
                l1 = l1.next;
            }else{
                d.next = l2;
                l2 = l2.next;
            }
            d = d.next;
        }
        if(l1!=null){ // 如果还有某个链表未遍历完,直接把后面的链到新链表即可
            d.next = l1;
        }
        if(l2!=null){
            d.next = l2;
        }
        return dummyNode.next;
    }
}

23. 合并K个升序链表

解法:

这就需要不断找出k个链表中的最小值了。怎么找?优先级队列。这是一个很好的东西,可以自定义比较器,选择队列中元素作比较

 代码:

class Solution {
    // 不断找出k个链表中的最小值,这就需要用到优先级队列
    // 优先级队列,可分为大堆和小堆,new的时候可以自定义比较器,来选择所有元素的max还是min
    public ListNode mergeKLists(ListNode[] lists) {
        if (lists.length == 0) { // 空集合
            return null;
        }
        ListNode dummyNode = new ListNode(-1);
        ListNode d = dummyNode;

        // 新建一个优先级队列,数值越小的Node,越先被选择
        PriorityQueue<ListNode> queue = new PriorityQueue<>(new Comparator<ListNode>() {
            @Override
            public int compare(ListNode o1, ListNode o2) {
                return o1.val - o2.val;
            }
        });
        // 把所有链表的头结点加入队列中
        for (ListNode head : lists) {
            if (head != null) {
                queue.offer(head);
            }
        }
        // 遍历队列,每次取出队头元素即为最小值
        while (!queue.isEmpty()) {
            ListNode top = queue.poll(); // 出队头
            d.next = top;
            if (top.next != null) { // 如果该结点仍有后续结点,直接入队
                queue.offer(top.next);
            }
            d = d.next;
        }
        return dummyNode.next;
    }
}

 

 

876. 链表的中间结点

图解:

代码:

class Solution {
    // 快慢双指针
    public ListNode middleNode(ListNode head) {
        ListNode fast = head;
        ListNode slow = head;
        while(fast!=null && fast.next!= null){
            fast = fast.next.next;
            slow = slow.next;
        }
        return slow;
    }
}

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

解法一:

删除倒数第N个节点,即删除正数第len-N+1个节点,因为不知道链表长度len,所以需要第一次遍历,得到节点个数len第二次遍历找到第len-N+1个结点

代码:

class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        int len = getLength(head);

        ListNode dummyNode = new ListNode(0);
        dummyNode.next = head;
        ListNode d = dummyNode;

        // 找到正数第m个节点的前一个节点
        for(int i=1;i<(len-n+1);i++){
            d = d.next;
        }
        // 让前一个节点执行m的后一个节点即删除第m个节点
        d.next = d.next.next;

        return dummyNode.next;// 返回头结点
    }
    public int getLength(ListNode head){
        int count = 0;
        while(head!=null){
            count++;
            head = head.next;
        }
        return count;
    }
}

解法二:

双指针,一次遍历即可:指针p1指向head,向前走n步,那么剩下的就是len-N步了,而我们正需要删除正数第len-N+1个节点,此时让p2指向head,p1和p2同时后移,直至p1.next为null,此时p2刚好指向正数第len-N+1个结点的前一个结点。

代码:

class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode dummyNode = new ListNode(-1);
        dummyNode.next = head;

        ListNode p1 = dummyNode;
        int i = 0;
        while (i < n) { // p1走n步,剩下的结点个数刚好是len-n个
            p1 = p1.next;
            i++;
        }
        ListNode p2 = dummyNode;
        while (p1.next != null) { // 若p1.next=null,那么我们已经找到了将被删除的节点的前一个几点
            p1 = p1.next;
            p2 = p2.next;
        }
        p2.next = p2.next.next;
        return dummyNode.next;
    }
}

141. 环形链表

解法:

快慢双指针,相遇即是有环

代码:

public class Solution {
    // 判断链表是否有环,快慢指针,快满指针相遇,即有环
    public boolean hasCycle(ListNode head) {
        if(head==null || head.next==null){ // 特殊情况
            return false;
        }
        ListNode fast = head;
        ListNode slow = head;
        
        while(fast!=null && fast.next!=null){
            fast = fast.next.next;  // 先移动,再比较
            slow = slow.next;

            if(fast==slow){ // 说明无环
                return true;
            }
        }
        return false;
    }
}

142. 环形链表 II

解法:

快慢双指针,相遇即是有环,若有环,让快慢其中一个指针和新的指针(指向head)同步长移动相遇即是入环的第一个节点

代码:

public class Solution {
    public ListNode detectCycle(ListNode head) {
        if(head==null){ // // 空链,必无环
            return null;
        }

        ListNode fast = head;
        ListNode slow = head;
        ListNode p = head;

        while(fast != null && fast.next != null){ // 但凡其中一个为null,则表示没有环
            fast = fast.next.next;
            slow = slow.next;
            if(fast == slow){ // 相遇表示有环

                while(slow != p){ // 新的指针指向head,和slow同步长移动,相遇即是入环结点
                    slow = slow.next;
                    p = p.next;
                }
                return p;
            }
        }
        return null;
    }
}

160. 相交链表

解法:

p1指向A,p2指向B,同步往前走,如果p1==null,p1指向B;如果p2==null,p2指向A,p1和p2相遇,即交点、

代码:

public class Solution {
    // p1指向A,p2指向B,一直往前走,如果p1==null,p1指向B,如果p2==null,p2指向A,直至p1和p2相遇,即交点
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        ListNode p1 = headA;
        ListNode p2 = headB;

        while(p1!=p2){ // 相遇即交点
            if(p1==null){
                p1 = headB;
            }else{
                p1 = p1.next;
            }
            if(p2==null){
                p2 = headA;
            }else{
                p2 = p2.next;
            }
        }
        return p1;
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Rust 是一种现代的编程语言,特别适合处理内存安全和线程安全的代码。在 LeetCode 中,链表是经常出现的题目练习类型,Rust 语言也是一种非常适合处理链表的语言。接下来,本文将从 Rust 语言的特点、链表的定义和操作,以及 Rust 在 LeetCode链表题目的练习等几个方面进行介绍和讲解。 Rust 语言的特点: Rust 是一种现代化的高性能、系统级、功能强大的编程语言,旨在提高软件的可靠性和安全性。Rust 语言具有如下几个特点: 1. 内存安全性:Rust 语言支持内存安全性和原语级的并发,可以有效地预防内存泄漏,空悬指针以及数据竞争等问题,保证程序的稳定性和可靠性。 2. 高性能:Rust 语言采用了“零成本抽象化”的设计思想,具有 C/C++ 等传统高性能语言的速度和效率。 3. 静态类型检查:Rust 语言支持静态类型检查,可以在编译时检查类型错误,避免一些运行时错误。 链表的定义和操作: 链表是一种数据结构,由一个个节点组成,每个节点保存着数据,并指向下一个节点。链表的定义和操作如下: 1. 定义:链表是由节点组成的数据结构,每个节点包含一个数据元素和一个指向下一个节点的指针。 2. 操作:链表的常用操作包括插入、删除、查找等,其中,插入操作主要包括在链表首尾插入节点和在指定位置插入节点等,删除操作主要包括删除链表首尾节点和删除指定位置节点等,查找操作主要包括根据数据元素查找节点和根据指针查找节点等。 Rust 在 LeetCode链表题目的练习: 在 LeetCode 中,链表是常见的题目类型,而 Rust 语言也是一个非常适合练习链表题目的语言。在 Rust 中,我们可以定义结构体表示链表的节点,使用指针表示节点的指向关系,然后实现各种操作函数来处理链表操作。 例如,针对 LeetCode 中的链表题目,我们可以用 Rust 语言来编写解法,例如,反转链表,合并两个有序链表,删除链表中的重复元素等等,这样可以更好地熟悉 Rust 语言的使用和链表的操作,提高算法和编程能力。 总之,在 Rust 中处理链表是非常方便和高效的,而 LeetCode 中的练习也是一个非常好的机会,让我们更好地掌握 Rust 语言和链表数据结构的知识。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值