当前位置: 首页 > news >正文

【算法】链表

  零:链表常用技巧

1:引入虚拟头结点

(1)便于处理边界情况

(2)方便我们对链表操作

2:两步尾插,头插 

(1)尾插

tail指向最后一个节点,tail.next 指向新尾节点,tail指针在指向新尾节点

(2)头插

新头结点.next = 虚拟头节点newhead.next

虚拟头节点newhead.next = 新头结点.

3:插入节点 

若有一个指针(next)指向被插入节点后的那个节点,那么这四句代码的顺序随意

反之,前两句必须写在前面(这两句顺序可以互换),后两句必须写在后面

一: 两数相加

2. 两数相加

/**
 * 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 addTwoNumbers(ListNode l1, ListNode l2) {
        //先new一个虚拟节点
        ListNode newHead = new ListNode(0);
        ListNode cur1 = l1 , cur2 = l2, cur3 = newHead;
        int t = 0;
        while(cur1 != null || cur2 != null || t != 0){
            //对第一个链表做加法
            if(cur1 != null){
                t += cur1.val;
                cur1 = cur1.next;
            }
            //对第二个链表做加法
            if(cur2 != null){
                t += cur2.val;
                cur2 = cur2.next;
            }
            //移动
            cur3.next = new ListNode(t%10);
            cur3 = cur3.next;
            t = t/10;
        }
        return newHead.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 swapPairs(ListNode head) {
        if (head == null || head.next == null) {
            return head;
        }
        // 虚拟头结点
        ListNode newHead = new ListNode(0);
        newHead.next = head;
        // 先搞四个指针
        ListNode prev = newHead, cur = prev.next, next = cur.next, nnext = next.next;
        while (cur != null && next != null) {
            prev.next = next;
            next.next = cur;
            cur.next = nnext;

            prev = cur;
            cur = nnext;
            if (cur != null) {
                next = cur.next;
            }
            if (next != null) {
                nnext = next.next;
            }
        }
        return newHead.next;

    }
}

三:143. 重排链表(写的酣畅淋漓的一道题 )

这道题涵盖了双指针,前插,尾插,合并两个链表,代码调试也很爽,很重要的是我们在变量的选择和名称定义上一定要规范,否则写代码就是一种折磨

 

/**
 * 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 void reorderList(ListNode head) {
        if(head == null || head.next == null || head.next.next == null) return ;
        // 1:找中间节点
        ListNode fast = head;
        ListNode slow = head;
        while (fast != null && fast.next != null) {
            slow = slow.next;
            fast = fast.next.next;
        }
        // 逆序准备工作:新的头结点
        ListNode head1 = head;
        ListNode head2 = new ListNode(0);
        ListNode cur = slow.next;
        slow.next = null;// 将上半段尾插null,分开标志

        // 2:逆序头插(很明显头插一直要用到的指针是头结点,这是关键),这里逆序链表头结点是虚拟节点注意注意!!!!
        while (cur != null) {
            ListNode tmp = cur.next;
            cur.next = head2.next;
            head2.next = cur;
            // cur = cur.next;错的cur更新为tmp,cur.next已经指向null了
            cur = tmp;
        }

        // 3:合并两个链表(尾插)双指针
        ListNode ret = new ListNode(0);
        ListNode prev = ret;
        ListNode cur1 = head1, cur2 = head2.next;
        while (cur1 != null) {// 左半链表长度>=右半
            // 先插左
            prev.next = cur1;
            cur1 = cur1.next;
            prev = prev.next;
            //  在插右
            if (cur2 != null) {
                prev.next = cur2;
                cur2 = cur2.next;
                prev = prev.next;
            }
        }

    }
}

四:合并K个升序链表

 23. 合并 K 个升序链表

这道题的解法有三种,暴力解法(超时),优先级队列(文章写法),递归(难)

复习了优先级队列的lambda表达式写法,爽,战斗爽!AC爽

/**
 * 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 mergeKLists(ListNode[] lists) {
        PriorityQueue<ListNode> queue = new PriorityQueue<>((v1, v2) -> v1.val - v2.val);// 小根堆
        // 放入第一批头结点
        for (ListNode head : lists) {
            if (head != null) {
                queue.offer(head);
            }
        }
        // 合并链表
        ListNode ret = new ListNode(0);
        ListNode cur = ret;// 定义指针
        while (!queue.isEmpty()) {
            ListNode tmp = queue.poll();
            cur.next = tmp;
            cur = cur.next;
            if (tmp.next != null) {
                tmp = tmp.next;
                queue.offer(tmp);
            }

        }
        return ret.next;
    }
}

五:K个一组翻转链表

25. K 个一组翻转链表

/**
 * 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 reverseKGroup(ListNode head, int k) {
        // 第一步计算需要逆序多少组 
        int n = 0;
        ListNode cur = head;
        while(cur != null){
            n++;
            cur = cur.next;
        }
        n = n/k;//逆序组数
        ListNode tmp = head;
        ListNode ret = new ListNode(0);
        ListNode prev = ret;
        while(n != 0){
            ListNode move = tmp;
            int m = k;
            while(m != 0){
                //执行k次头插法
                ListNode next = tmp.next;
                tmp.next = prev.next;
                prev.next = tmp;
                tmp = next;
                m--;
            }
            prev = move;
            n--;
        }
        prev.next = tmp;
        return ret.next;

    }
}

六:相交链表

力扣k神的图解,真的nb,太清晰了

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

七:回文链表

心得:

1:尽量画图

2:确定中间节点的时候,奇数个节点好理解,偶数个节点指向的是右边那个节点

3:反转链表后原链表并没有断开

4:反转链表有两种方法,第一种搞一个虚拟头结点,进行头插,第二种递归。战斗爽!塔塔开

/**
 * 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 boolean isPalindrome(ListNode head) {
        ListNode mid = midNode(head);
        ListNode reverseHead = reverseList2(mid);
        //没有断
        while(reverseHead != null){
            if(head.val != reverseHead.val){
                return false;
            }
            head = head.next;
            reverseHead = reverseHead.next;
        }
        return true;
    }

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

    public ListNode reverseList(ListNode head){
        //new 虚拟null节点
        ListNode pre = null;
        ListNode cur = head;
        //头插
        while(cur != null){
            ListNode tmp = cur.next;
            cur.next = pre;
            pre = cur;
            cur = tmp;
        }
        return pre;
    }

    public ListNode reverseList2(ListNode head){
        //递归的方法,head等不等于null,就是以防给的是空链表
        if(head == null || head.next == null){
            return head;
        }
        ListNode newHead = reverseList(head.next);//新的头结点
        head.next.next = head;
        head.next = null;
        return newHead;

    }

}

 八:环形链表

心得:快慢双指针,秒了

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

相关文章:

  • Unity Shader学习6:多盏平行光+点光源 ( 逐像素 ) 前向渲染 (Built-In)
  • Word中接入大模型教程
  • 深度学习框架探秘|Keras:深度学习的魔法钥匙
  • 最新智能优化算法: 贪婪个体优化算法(Greedy Man Optimization Algorithm,GMOA)求解23个经典函数测试集,MATLAB代码
  • Vivado生成edif网表及其使用
  • 高效学习方法分享
  • Python学习心得常见的异常
  • Redis 主从复制
  • Mybatis后端数据库查询多对多查询解决方案
  • Lombok注解@EqualsAndHashCode
  • apache artemis安装
  • Git 使用指南:避免使用 merge 的完整流程
  • python学opencv|读取图像(六十七)使用cv2.convexHull()函数实现图像轮廓凸包标注
  • Ubuntu 下 nginx-1.24.0 源码分析 - ngx_create_pool函数
  • 《第三代大语言模型Grok 3:闪亮登场》
  • OpenCV(1):简介、安装、入门案例、基础模块
  • Qt 中使用 SQLite 数据库的完整指南
  • DeepSeek 的创新融合:多行业应用实践探索
  • 网络安全攻防演练——RT实战技巧篇
  • ELK 日志收集框架搭建
  • 上海银行副行长汪明履新上海农商银行党委副书记
  • 旅马大熊猫“福娃”“凤仪”平安回国
  • 东航C919航线上新!正式投入上海虹桥—深圳航线运营
  • 天算星座二期首批卫星成功发射,将助力6G空天信息基础设施建设
  • 武康大楼再开发:一栋楼火还不够,要带火街区“朋友圈”
  • 陕西省市监局通报5批次不合格食品,涉添加剂超标、微生物污染等问题