当前位置:   article > 正文

Leetcode链表刷题总结(Java版)

Leetcode链表刷题总结(Java版)

链表

1、移除链表元素(考虑全情况)

问题需求:根据给定的val值,移除链表中值是这个val的节点

203. 移除链表元素 - 力扣(LeetCode)

这里有一个问题就是,如果需要被移除的节点不是中间的某个节点,而是头节点。就没法借助前一个节点了,而是直接将

head = head.next

所以有两种思路,要么是分类处理;要么是在原本的head节点前面增加一个虚拟头节点,这样头节点也有个前面的节点了

还有需要注意的是,这里的代码,不应该用if,因为我们是一直移除的一个过程,所以应该用while

  • 思路一:
public ListNode removeElements(ListNode head, int val) {
    while(head != null && head.val == val)  //之所以不用if,是因为可能从头结点开始有连续的等于val的节点
        head = head.next;
    ListNode cur = head;		//删除非头节点情况
    while(cur != null && cur.next != null){
        if(cur.next.val = val)
            cur.next = cur.next.next;
        else
            cur = cur.next;
    }
    return head;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 思路二:
ListNode dummyHead = new ListNode(0); // 设置⼀个虚拟头结点
dummyHead.next = head; 			// 将虚拟头结点指向head,这样⽅⾯后⾯做删除操作
ListNode cur = dummyHead;
while(cur.next != null){
    ...
}
return dummyHead.next;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

2、设计链表【个人觉得想熟悉链表时可以练这个】

在这里插入图片描述

就是实现关于链表的各个操作,为了方便,还是用上了虚拟头节点

初始化中的0就是虚拟头节点了

3、反转链表(双指针)

206. 反转链表 - 力扣(LeetCode)

双指针法

遍历链表,按照头插法,将旧链表的一个个节点放到新链表的头节点,最后反转成功

public ListNode reverseList(ListNode head) {
    ListNode cur = head;
    ListNode first = null;
    while(cur!=null){
        ListNode tmp = cur.next;    // 保存⼀下 cur的下⼀个节点,因为接下来要改变cur->next
        cur.next = first;           //头部插入
        //更新双指针
        first = cur;
        cur = tmp;
    }
    return first;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

4、两两交换链表中的节点(借助虚拟头节点)

24. 两两交换链表中的节点 - 力扣(LeetCode)

在这里插入图片描述

需要借助虚拟头节点,这样操作会简单一点

每次需要一个指针cur指向需要被交换的两个节点,的前一个节点

顺序就是,虚拟头节点先指向2,然后让2指向1,最后1指向3。而这里的“1”和“3”是需要两个临时节点记录一下

public ListNode swapPairs(ListNode head) {
    ListNode  dummyHead = new ListNode(0);
    dummyHead.next = head;
    ListNode cur = dummyHead;
    while(cur.next != null && cur.next.next != null){
        ListNode tmp = cur.next;
        ListNode tmp1 = cur.next.next.next;
        cur.next = cur.next.next;
        cur.next.next = tmp;
        cur.next.next.next = tmp1;
        cur = tmp;                  // 或者cur = cur.next.next;  cur移动两位,准备下⼀轮交换
    }
    return dummyHead.next;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

5、删除链表倒数第N个节点(快慢指针)

19. 删除链表的倒数第 N 个结点 - 力扣(LeetCode)

  • 由于需要删除的是倒数第N个,所以可以用快慢指针

  • 双指针的经典应⽤,如果要删除倒数第n个节点,让fast移动n步,然后让fast和slow同时移动,直到fast指向链表末尾。删掉slow所指向的节点就可以了

  • 这里需要注意的就是,需要虚拟头节点,考虑到了如果链表只有一个元素,或者只有两个元素的情况

    这种时候,用到虚拟头节点,就很好的可以处理

    另外,最后返回的时候,不要返回head,而是返回dummyhead.next,因为如果只有一个节点的情况,删除后,就没有head,就知识null了,所以不能返回head

public ListNode removeNthFromEnd(ListNode head, int n) {
    ListNode dummyhead = new ListNode(0);
    dummyhead.next = head;
    ListNode fast = dummyhead;
    ListNode slow = dummyhead;
    for(int i = 0; i < n; i++)
        fast = fast.next;
    fast = fast.next;			 // fast再提前⾛⼀步,因为需要让slow指向删除节点的上⼀个节点
    while(fast != null){      
        slow = slow.next;
        fast = fast.next;
    }
    slow.next = slow.next.next;
    return dummyhead.next;      //不能返回head,只能是dummyhead.next
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

6、链表相交:寻找两个链表(无环结构)重合结点

面试题 02.07. 链表相交 - 力扣(LeetCode)

  • 其实这个链表问题主要需要总结的就是那些经验及方法,而对于两个无环结构的链表,就是常规方法

    ​ 先是求出连两个链表的长度length1,length2,然后就是需要判断这两个链表的尾结点是不是一样的

    ​ 如果连尾结点都不一样,就说明两个链表连一个结点都没有重合,所以两个链表绝对不会重合

    如果尾结点一样的话,需要将两个链表的长度互减

    ​ 然后这个数num的绝对值就是这两个链表长度的差值,**让长链表提前走num步,然后两个链表再同时走,**直到遇见了相同的交点处停下来返回此结点,具体代码如下:

    public static Node noLoop(Node head1, Node head2) {
        if (head1 == null || head2 == null) {	return null;   }
        Node cur1 = head1;
        Node cur2 = head2;
        int n = 0;                      //这里为了简化以及节省空间,就设置了一个变量n,通过下面的两个while循环,一个自加,一个自减,最后求他的绝对值,就是两个链表的长度差值
        while (cur1.next != null) {
            n++;
            cur1 = cur1.next;}
        while (cur2.next != null) {
            n--;
            cur2 = cur2.next;}
        if (cur1 != cur2) {			   //如果最后一个结点都不一样,那么两个链表绝对不可能有交合的地方了
            return null;              
        }
        cur1 = n > 0 ? head1 : head2;			//谁长,谁的头变成cur1
        cur2 = cur1 == head1 ? head2 : head1;	 //谁短,谁的头变成cur2
        n = Math.abs(n);
        while (n != 0) {			  //先让长链表走了n步
            n--;
            cur1 = cur1.next;
        }
        while (cur1 != cur2) {		  //开始寻找相交结点
            cur1 = cur1.next;
            cur2 = cur2.next;
        }
        return cur1;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

7、环形链表

142. 环形链表 II - 力扣(LeetCode)

划分为两个问题:

  1. 判断有环无环
  2. 如果有环的话,找到环的起始节点

1)判断有环无环

判断链表是否有环,可以借助哈希表set,也可以用快慢指针,

**1)哈希表set:**将所有节点放进set中,每放进去一个节点都查查这个节点是不是在集合中,第一次查到这个节点在集合中的时候,就说明这个节点就是环的起点

2)快慢指针: 只要最后不会指向空【如果快指针指向空了,就说明没有环】,并且快慢指针重合,就说明该链表又环。判断有环之后,就要开始找环的起始点,看下面的描述

//哈希表set
public static boolean hasCycle(Node head){
    HashSet<Node> set = new HashSet<Node>();
    set.add(head);
    Node cur = head.next;
    while(true){
        if(set.contains(cur))
            return true;
        else{
            set.add(cur);
            cur=cur.next;
            if(cur==null)
                return false;
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
//快慢指针
public static boolean ifCycle(Node head){
	Node slow = head;
    Node fast = head.next;
    while(fast != slow){
        if(fast == null)
            return false;
        slow = slow.next;
        fast = fast.next.next;
    }
    return true;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

2)找到环的起始节点

这里一开始还是借助快慢指针,先是判断有无环结构:

  1. 如果有环的话,也就是说快慢指针在环上的某一个结点上重合了。(这是第一个while循环)

  2. 此后就到了本方法的骚气处了【这是通过公式推导出来的规律!!记住这个结论!!!】

    • 将快指针转移到头结点的位置,慢节点还是在原来环上面两个指针相遇的位置
    • 快慢指针的的移动步长都变为一
    • 此时他们再相遇重合的那个位置就是环结点的起始处了(这是第二个while循环),直接上代码:
public ListNode detectCycle(ListNode head) {
    ListNode fast = head;
    ListNode slow = head;
    while(fast != null && fast.next != null){
        fast = fast.next.next;
        slow = slow.next;
        if(slow == fast)
            break;
    }
    if(fast == null || fast.next == null)  //跳出上面循环时有两种可能,一是没有环,另外就是slow == fast。所以需要判断如果										//无环的话,直接返回null
        return null;
    fast = head;
    while(fast != slow){
        fast = fast.next;
        slow = slow.next;
    }
    return fast;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

8、判断回文结构

借助栈

public static boolean isPalindrome1(Node head) {
	Stack<Node> s = new Stack<Node>();
    Node cur = head;
    while(cur != null){
        s.push(cur);
        cur = cur.next;
    }
    cur = head;
    while(head != null){
        if(head.val != s.pop().val)
            return false;
        head = head.next;
    }
   return true; 
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

本文是基于学习代码随想录,以及自刷leetcode总结链表方面的笔记,不仅仅限于代码随想录笔记,是一些自己的思考和整理。并且是Java版本

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/523686
推荐阅读
相关标签
  

闽ICP备14008679号