常见链表的操作题+代码

文章目录

    • [leetcode 2 两数相加](#leetcode 2 两数相加)
    • [leetcode 19删除链表中的倒数第N个节点](#leetcode 19删除链表中的倒数第N个节点)
    • [leetcode 21合并两个有序链表](#leetcode 21合并两个有序链表)
    • [leetcode 24两两交换链表中的节点](#leetcode 24两两交换链表中的节点)
    • [leetcode 25k个一组链表反转](#leetcode 25k个一组链表反转)
    • [leetcode 61旋转链表](#leetcode 61旋转链表)

leetcode 2 两数相加

两个链表对应的值进行相加,如何计算呢?

考虑点,如果长度为3的,和长度为2的如何计算,应该是左对齐的,到第三位的时候,如果为null,应该返回值0,这里可以采用三元运算符来求解

采用虚拟的头节点;

如何解决进位问题呢?讲x+y取模10,对应的是哪个位上的值,然后(x+y)/10得到如果大于1,就是往前进了一个,那么需要加入到下一次的循环中去,循环的条件就是两个对应的指针有一个不为null即可。

解决进位问题,

csharp 复制代码
class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {

        //为什么学完总是忘记呢?
        //pre是这个节点的最前面的,cur等于当前的节点。
        ListNode pre=new ListNode(0); //创建的一个节点
        ListNode cur=pre;
        int carry=0;
        while (l1!=null||l2!=null){
            //这边的小技巧,采用三元运算符
            int x=l1==null?0:l1.val;
            int y=l2==null?0:l2.val;
            int sum=x+y+carry;

            carry=sum/10;

            sum=sum%10;

            cur.next=new ListNode(sum);

            cur=cur.next;

            //l1和l2往下进行移动
            if (l1!=null)
            {
                l1=l1.next;
            }
            if (l2!=null){
                l2=l2.next;
            }
          }

        if (carry==1){
            cur.next=new ListNode(carry); //后面在添加一个节点
        }
        return pre.next;

    }
}

leetcode 19删除链表中的倒数第N个节点

直接操作是不知道对应链表的长度的,那么如何操作呢?

可以遍历一遍对应的链表获取到当前链表的长度。

这道题为什么需要设置头节点,设置一个头节点,走N次,身下K-N次,然后两个节点都走K-N次,刚好是倒数第N个节点,不太好操作,只是知道当前的节点而已,不知道下面的节点。

那么如何操作呢?需要加入头节点,这样就会在倒数第k-N+1个节点的位置,那样即可删除掉倒数第N个节点。

csharp 复制代码
class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode dummy = new ListNode(0, head);
        
        ListNode first = head;
        
        ListNode second = dummy;
        
        for (int i = 0; i < n; ++i) {
            first = first.next;
        }
        while (first != null) {
            first = first.next;
            second = second.next;
        }
        //删除倒数第N个节点;
        second.next = second.next.next;
        
        ListNode ans = dummy.next;
        
        return ans;
    }
}

leetcode 21合并两个有序链表


csharp 复制代码
class Solution {
    public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
         //讲两个升序链表合并为新的升序链表返回。

        //递归方式不断往里面去走,结束的条件就是有一个为null,直接返回;
        if (list1==null){
            return list2;
        }else if (list2==null){
            return list1;
        }else if (list1.val<list2.val){
            //如果l1小,那么就需要合并l1
            list1.next=mergeTwoLists(list1.next,list2);
            return list1;
        }else{
            //合并l2,
            list2.next=mergeTwoLists(list1,list2.next);
            return list2;
        }
    }
}

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

csharp 复制代码
class Solution {
    public ListNode swapPairs(ListNode head) {
         //两两交换链表中的节点
        //递归解法
        if (head==null||head.next==null){
            return head;
        }
        ListNode next=head.next;
        head.next=swapPairs(next.next); //不断的往里面进行递归,不断的调用,到head==null或者下面等于null返回

        next.next=head;
        //返回头节点等于head;
        return next;
    }
}

不采用递归的方式去写,采用循环的方式,链表之间的操作去写。定义一个虚拟头节点dummy,定义一个cur指针指向虚拟头节点,条件需要的是因为两两交换需要cur.next和cur.next.next都不为null才可以;

leetcode 25k个一组链表反转

这道题有多个部分组成的,首先是反转单链表需要知道,然后如何处理k个一组的链表,反转之后如何操作

设置的双指针的思想,end指针先移动k个,然后讲后面的断掉,反转start指针的链表,反转之后end在前面了,start在后面了,讲start和后面的节点继续连接起来,然后end和pre节点都回到start上面开始下一次的遍历,如果遍历的时候end指向了null说明是最后节点是不用反转的,此时只需要break结束循环;

csharp 复制代码
class Solution {
    public ListNode reverseKGroup(ListNode head, int k) {
          ListNode dummy=new ListNode(0);
          dummy.next=head;
          ListNode pre=dummy;
          ListNode end=dummy; //虚拟节点
        //没k组进行反转,如果小于k组那么就不需要反转

        //反转单链表,可以采用递归的方式,也可以不用递归;

        while (end.next!=null){
            //从头节点开始 移动k位
            for (int i=0;i<k && end!=null;i++) end=end.next; //移动k位;
            if (end==null) break; //如果当前位null就直接结束了
            ListNode start=pre.next;
            ListNode next=end.next; //为了下一次的连接

            end.next=null; //断开连接
            pre.next=reverse(start);

            start.next=next; //反转之后start是结尾了,在连起来

            pre=start; //移动位置,讲pre 和end连接到start上面
            end=pre;
        }
        return dummy.next;
    }

    //反转一个节点
    public  ListNode reverse(ListNode head){
        ListNode pre=null;
        ListNode curr=head;
        while (curr!=null){
            ListNode next= curr.next;
            curr.next=pre;
            pre=curr;
            curr=next;
        }
        return  pre;
    }
}

leetcode 61旋转链表

思路 旋转链表

讲链表向右移动k位

计算链表的长度为n,需要计算k%n,如果等于0,操作了对应长度的次数,那么链表还是不会发生变化的。

占村现在的尾节点,尾节点最后指向最后前部分的节点。

while循环让node指向到n-k个,tail.next=head;

ListNode newHead=node.next; //开始了新的节点,最后需要将这个节点的下一个为null。

防止链表成环。

csharp 复制代码
class Solution {
    public ListNode rotateRight(ListNode head, int k) {
            //讲最后一个节点断开指向第一个节点
        //如何找到最后一个节点呢?
        if (head==null) return head; // 链表为空直接返回

        ListNode node=head; //用于遍历链表和定位尾节点
        int n=1;//初始值尾1,表示头节点

        while (node.next!=null){
            n++;
            node=node.next; //遍历对应的节点
        }

        k%=n; //k除以n
        if (k==0) return head; //反转n次相当于不变的
        //tail尾节点
        ListNode tail=node ;//暂存头节点。最后的尾节点,尾节点来拼接前半部分的节点的
        //node有重新回到头节点
        node=head;

        while (n-->k+1) node=node.next; //向右移动k次,需要先移动

        tail.next=head;//玮节点指向头节点
        // 重新拼接[1, n - k]部分节点和[n - k + 1, n]部分节点,即变为[n - k + 1, n] + [1, n - k]
        //newhead等于node的下一个,就是对应的后面新节点
        ListNode newHead=node.next;

        node.next=null; //对的这边起始是没有切掉的2后面就是对应的新节点,然后需要讲2后面的切掉,不然链表就会成环了

        return newHead;

    }
}

真正的双指针代码

csharp 复制代码
class Solution {
    public ListNode rotateRight(ListNode head, int k) {
    //
        if (head==null){
            return head;
        }
        int len=calculate(head);

        k=k%len;

        ListNode slow=head;
        ListNode fast=head;

        for (int i=0;i<k;i++){
            fast=fast.next;
        }
        //n-k步
        while (fast.next!=null){
            fast=fast.next;
            slow=slow.next;
        }
        //此时slow在n-k步,后面就是对应的k步,将后面的k步指向前面的,最后再将head改为slow.next;

        fast.next=head;
        //这个时候发现链表成环了

        head=slow.next;

        slow.next=null; //去掉环

        return head;
    }
    //计算链表的长度
    public int calculate(ListNode head){
        int len=0;
        while (head!=null){
            head=head.next;
            len++;
        }
        return  len;
    }
}
相关推荐
wclass-zhengge12 分钟前
04树 + 堆 + 优先队列 + 图(D1_树(D6_B树(B)))
数据结构·b树
星如雨グッ!(๑•̀ㅂ•́)و✧29 分钟前
Java NIO全面详解
java·python·nio
taopi20242 小时前
android java系统弹窗的基础模板
android·java·开发语言
松仔log2 小时前
Java多线程——对象的组合
java·开发语言·jvm
qq_433618442 小时前
哈夫曼树
数据结构·算法
酷爱码3 小时前
springboot 动态配置定时任务
java·spring boot·后端
从未止步..3 小时前
Jenkins未在第一次登录后设置用户名,第二次登录不进去怎么办?
java·运维·jenkins
老马啸西风3 小时前
IM 即时通讯系统-42-基于netty实现的IM服务端,提供客户端jar包,可集成自己的登录系统
java
2501_903238653 小时前
Java 9模块开发:Eclipse实战指南
java·开发语言·eclipse·个人开发
励志成为美貌才华为一体的女子3 小时前
python算法和数据结构刷题[4]:查找算法和排序算法
数据结构·算法·排序算法