链表题解(上)

1.给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。19. 删除链表的倒数第 N 个结点 - 力扣(LeetCode)

示例:给定一个链表:1->2->3->4->5,和n = 2。当删除了倒数第二个节点后,链表为1->2->3->5

说明:题目保证给的n是一个有效的数据

方法一:暴力求解

(1)求得链表的长度

(2)删除丛链表头数起的第(L-n+1)个节点

方法二:快慢指针法

识别的方法:1.涉及链表的特殊位置,考虑快慢指针;2.要删除链表节点,找他的前驱

思路:

1.创建一个新的头节点newNode,newNode.next指向headNode。创建两个指针fast、slow。fast = headNode;slow = newNode;

2.先让fast走n步

3.然后fast和slow一起走,当fast==null时,此时的slow节点的下一个节点就是要删除的节点,则slow.next = slow.next.next;返回头结点的下一个节点,即newNode.next;

示意图:

class Solution {
    public ListNode removeNthFromEnd(ListNode headNode, int n) {
        ListNode fristNode = new ListNode(0,headNode);//在头节点之前设置一个节点
        ListNode fast = headNode;
        ListNode slow = fristNode;
        while(n>0){//这里的n是有效的数据,不会使发生空指针异常
            fast = fast.next;
            n--;
        }
        while(fast!=null){//如果fast==null就说明要删除的就是头结点
            fast = fast.next;
            slow = slow.next;
        }
        slow.next = slow.next.next;
        ListNode ans = fristNode.next;
        return ans;
    }
}

 结果:

2.2. 两数相加 - 力扣(LeetCode)

给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。

请你将两个数相加,并以相同形式返回一个表示和的链表。

你可以假设除了数字 0 之外,这两个数都不会以 0 开头。

例如:

输入:l1 = [2,4,3], l2 = [5,6,4]
输出:[7,0,8]
解释:342 + 465 = 807
输入:l1 = [0], l2 = [0]
输出:[0]

思路:

(1)两个数相加,满十进一(carry =sum/10)。将两个加数的和sum%10以后放在一个新的节点里

(2)满足条件(链表l1!=null和l2!=null),继续执行相加操作。当不满足条件(链表l1!=null和l2!=null) 以后,在判断carry是否大于1,如果大于1说明还要创建一个节点来接收这个数

class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        ListNode head = null, tail = null;
        int carry = 0;
        while (l1 != null || l2 != null) {
            int n1 = l1 != null ? l1.val : 0;
            int n2 = l2 != null ? l2.val : 0;
            int sum = n1 + n2 + carry;
            if (head == null) {
                head = tail = new ListNode(sum % 10);
            } else {
                tail.next = new ListNode(sum % 10);
                tail = tail.next;
            }
            carry = sum / 10;
            if (l1 != null) {
                l1 = l1.next;
            }
            if (l2 != null) {
                l2 = l2.next;
            }
        }
        if (carry > 0) {
            tail.next = new ListNode(carry);
        }
        return head;
    }
}

结果

3.两两交换链表中的节点:给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成。示例:[1,2,3,4]->[2,1,4,3];[1]->[1];[]->[];24. 两两交换链表中的节点 - 力扣(LeetCode)

 方法一:利用快慢指针

* 思路:
* 1.检查头结点是否为空,是则返回null
* 2.在头节点之前创建一个新节点D,D.next = head;创建两个指针fast、slow,fast == D;slow == head;
* 3.先让fast = fast.next.next;检查fast是否等于null,是则返回D.next;
* 4.若第3步fast!=null,以slow!=null&&fast!=null为循环条件,依次找到奇偶结点进行交换(在交换过程中,若slow = slow.next.next;slow==null;则直接return D.next)
* 5.最终返回D.next;
    public Node swapPairs(Node head) {
        if(head==null){
            return head;
        }
        Node D = new Node(0, head);
        Node fast = D;
        Node slow = head;
        fast = fast.next.next;
        Node temp = new Node(-1);
        if(fast==null){//成立,则说明链表中只有一个节点
            return D.next;
        }
        while(slow!=null&&fast!=null){
            temp.no = fast.no;
            fast.no = slow.no;
            slow.no = temp.no;
            slow = slow.next.next;
            if(slow==null){
                return D.next;
            }
            fast = fast.next.next;
        }
        return D.next;
    }

主函数里面实现一下

    public static void main(String[] args) {//验证交换两个节点
        Linkedlist linkedlist1 = new Linkedlist();
        linkedlist1.finallAdd(1);
        linkedlist1.finallAdd(2);
        linkedlist1.finallAdd(3);
        linkedlist1.finallAdd(4);
        linkedlist1.printList();
        System.out.println("================");
        Linkedlist.Node node = linkedlist1.swapPairs(linkedlist1.headNode);
        linkedlist1.printList(node);
    }

 结果

方法二:递归

递归的出口,就是当链表为空或者链表中只有一个节点的情况,此时返回头结点。

令head为头结点,headNext为头结点的下一个节点,如果这两个节点交换以后,headNext就是新的头结点, 返回headNext即可。

剩下的节点的头结点是headNext的下一个节点就是headNext.next。此时的headNext.next就是head,它的下一个节点是headNext。然后一直递归下去,直到遇到出口就一层层的返回。

    public Node recursiveswap(Node head){
        if(head==null||head.next==null){
            return head;
        }
        Node headNext = head.next;
        head.next = recursiveswap(headNext.next);
        headNext.next = head;
        return headNext;
    }

 主函数里面实现一下

    public static void main(String[] args) {//验证交换两个节点
        Linkedlist linkedlist1 = new Linkedlist();
        linkedlist1.finallAdd(1);
        linkedlist1.finallAdd(2);
        linkedlist1.finallAdd(3);
        linkedlist1.finallAdd(4);
        linkedlist1.printList();
        System.out.println();
        System.out.println("================");
        Linkedlist.Node node = linkedlist1.recursiveswap(linkedlist1.headNode);
        linkedlist1.printList(node);
    }

结果

 4.旋转链表61. 旋转链表 - 力扣(LeetCode)

思路:

1.遍历到最后一个节点,将最后一个节点last的next只想头结点

2.head和last一起移动n = len-k%len个位置

3.将last的next置为空 

4.返回旋转以后新链表

class Solution {
    public ListNode rotateRight(ListNode head, int k) {
        if(head==null||head.next==null){//没有节点或者只有一个节点的情况,直接返回头结点
            return head;
        }
        int len = 1;//用来计算链表的长度
        ListNode temp = head;
        while(temp.next!=null){//这里要保留最后一个节点
            len++;
            temp = temp.next;
        }
        ListNode last = temp;//记录最后一个节点
        last.next = head;//让最后一个节点指向头结点
        int n = len-k%len;//头结点和尾节点移动次数
        while(n-->0){
            head = head.next;
            last = last.next;
        }
        last.next = null;
        return head;
    }
}

结果

5.删除已经排过序链表中重复的数字 83. 删除排序链表中的重复元素 - 力扣(LeetCode)

思路:

判断当前节点cur.val是否与下一个节点cur.next.val相等。相等则让当前节点的next指向下一个节点的下一个节点,即cur.next = cur.next.next。

不相等,则让当前节点跳向下一个节点cur = cur.next

继续上面的判断cur.next是否等于null,也就是cur.next所指向的那个节点是否为空,不为空则重复上面的操作,为空则返回head

class Solution {
    public ListNode deleteDuplicates(ListNode head) {
        if (head == null) {
            return head;
        }

        ListNode cur = head;
        while (cur.next != null) {
            if (cur.val == cur.next.val) {
                cur.next = cur.next.next;
            } else {
                cur = cur.next;
            }
        }

        return head;
    }
}

 结果

6.删除已经排过序链表中重复的所有数字 82. 删除排序链表中的重复元素 II - 力扣(LeetCode)

思路:

创建一个新的头结点newhead,这个头结点指向head,同时创建两个指针cur、temp。 cur = newhead;temp = head;

temp.val与temp.next.val比较

1.相等,则记录当前的值val,如果当前的temp!=null且值为val,则让temp = temp.next。继续判断temp是否为空,且temp.val是否等于val。相等则继续temp = temp.next。不相等,则cur.next = temp

2.不相等则cur = temp;temp = temp.next

3.然后再执行上面的操作,直到temp等于空或者temp.next == null;退出循环,返回newhead.next

class Solution {
    public ListNode deleteDuplicates(ListNode head) {
        if(head==null){//链表中没有节点
            return head;
        }
        ListNode newhead = new ListNode(-1,head);
        ListNode cur = newhead;
        ListNode temp = head;
        while(temp!=null&&temp.next!=null){
            if(temp.val==temp.next.val){
                int num = temp.val;//记录当前位置的值
                while(temp!=null&&temp.val==num){
                    temp = temp.next;
                }
                cur.next = temp;
            }
            else{
                // cur.next = temp;
                // cur = cur.next;
                cur = temp;
                temp = temp.next;
            }
        }
        return newhead.next;
    }
}

 结果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

咸鱼吐泡泡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值