第13章—指针三剑客之一:链表

13.1 数据结构的介绍

链表是由节点和指针构成的数据结构,每个节点存有一个值,和一个指向下一个节点的指针,因此很多链表问题可以用递归来处理。不同于数组,链表并不能直接获取任意节点的值,必须要通过指针找到该节点后才能获取其值。同理,在未遍历到链表结尾时,我们也无法知道链表的长度,除非依赖其他数据结构储存长度。

由于在进行链表操作时,尤其是删除节点时,经常会因为对当前节点进行操作而导致内存或指针出现问题。有两个小技巧可以解决这个问题:**一是尽量处理当前节点的下一个节点而非当前节点本身,二是建立一个虚拟节点 (dummy node),使其指向当前链表的头节点,**这样即使原链表所有节点全被删除,也会有一个 dummy 存在,返回 dummy->next 即可。

13.2 链表的基本操作

题目代号: 206 反转链表

题目描述:

翻转一个链表

测试用例:

输入:head = [1,2,3,4,5]
输出:[5,4,3,2,1]

我的分析:

在这里插入图片描述
1、把当前指针的后面扔给中转站
2、当前指针指向头节点的下一个节点
3、头节点指向当前指针节点
4、指针后移

代码:

public ListNode reverseList(ListNode head) {
        ListNode HummyHead = new ListNode(0);
        ListNode temp = head;//指针指向头节点
        while (temp != null) {
            ListNode zhongzhuan = temp.next;//把当前指针的下一个节点给中转站
            temp.next = HummyHead.next;//当前节点指向头节点的下一个节点
            HummyHead.next = temp;//哑节点指向当前节点
            temp = zhongzhuan;//指针指向中转站
        }
        return HummyHead.next;

    }

题目代号: 21 合并两个有序链表

题目描述:

给定两个增序的链表,试将其合并成一个增序的链表

测试用例:

Input: 1->2->4, 1->3->4
Output: 1->1->2->3->4->4

我的分析:

这思路很容易理解,就新建一个带哑节点的链表,并让temp指针指向它

两个指针依次向后移动,看谁小,就把谁挂到temp上,temp向后移动一位

出了这个while循环,那就只剩一个链表了,那就把这个链表挂到temp上即可

代码:

public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        ListNode zong = new ListNode(0),temp = zong;//指向总链表的指针
        while (l1 != null && l2 != null){//出了这个while循环,那就肯定有个链表结束了,还剩另一条链表
            if(l1.val <= l2.val){
                temp.next = l1;
                l1 = l1.next;
            }else {
                temp.next = l2;
                l2 = l2.next;
            }
            temp = temp.next;//总链表的指针向后移动
        }
          // if(l1 != null){
          //   temp.next = l1;
          // }else{
          //   temp.next = l2;
          // }

        temp.next = l1 != null? l1:l2;//temp指针指向剩下的链表
        return zong.next;
    }

题目代号: 24 两两交换链表中的节点

题目描述:

给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。

测试用例:

输入:head = [1,2,3,4]
输出:[2,1,4,3]

我的分析:
在这里插入图片描述
temp相当于总节点
1、2两个步骤相当于把这个链表扯开了
真的很有讲究,记住这个指向的顺序

代码:

public ListNode swapPairs(ListNode head) {
        ListNode dummyHead = new ListNode(0, head);
        ListNode temp = dummyHead;//搞个哑节点,然后指向它
        while (temp.next != null && temp.next.next != null) {
            ListNode node1 = temp.next;
            ListNode node2 = temp.next.next;//其实是可以把指针里的数据放到新定义的节点里的
            temp.next = node2;//准确的说只有当等号前的的代号有next的时候,就是指向,而如果没有next的话,就是赋值
            node1.next = node2.next;
            node2.next = node1;
            temp = temp.next.next;
        }
        return dummyHead.next;
    }

题目代号: 160 相交链表

题目描述:

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

测试用例:

在这里插入图片描述

我的分析:

假设链表 A 的头节点到相交点的距离是 a,链表 B 的头节点到相交点的距离是 b,相交点到链表终点的距离为 c。我们使用两个指针,分别指向两个链表的头节点,并以相同的速度前进,若到达链表结尾,则移动到另一条链表的头节点继续前进。按照这种前进方法,两个指针会在a + b + c 次前进后同时到达相交节点。

指针temp1移动走向:a+c+b+c
指针temp2移动走向:b+c+a+c

代码:

public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        ListNode temp1 = headA;
        ListNode temp2 = headB;
        while (temp1 != temp2){//当不相等的时候,就一直向后移动
            temp1 = temp1 == null ? headB:temp1.next;
            temp2 = temp2 == null ? headA:temp2.next;
            // if(temp1 == null){
            //     temp1 = headB;//temp1移动完了headA,那就去headB开始移动
            // }else{
            //     temp1 = temp1.next;//没移动完就接着移动
            // }
            // if(temp2 == null){
            //     temp2 = headA;
            // }else{
            //     temp2 = temp2.next;
            // }
        }
        return temp2;//你就说说这个方法有多牛逼,temp1遍历完headA就去遍历headB
        //temp2遍历完headB就去遍历headA,所以最后几位数肯定会相遇的,相遇就跳出循环,return那位数,不相遇就一直到最后,return null
    }

题目代号: 234 回文链表

题目描述:

请判断一个链表是否为回文链表。

测试用例:

Input: 1->2->3->2->1
Output: true

我的分析:

这方法真的绝了,直接放进一个数组中,然后左右遍历,看不相同就直接返回false,全部相同就返回true

代码:

 public boolean isPalindrome(ListNode head) {
        List<Integer> list = new ArrayList<Integer>();

        // 将链表的值复制到数组中
        ListNode temp = head;
        while (temp != null) {
            list.add(temp.val);
            temp = temp.next;
        }

        // 使用双指针判断是否回文
        int left = 0;
        int right = list.size() - 1;
        while (front < right) {
            if (!list.get(left).equals(list.get(right))) {
                return false;
            }
            left++;
            right--;
        }
        return true;
    }
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值