链表汇总

先刷题,在总结

文章目录

剑指 Offer 06. 从尾到头打印链表

在这里插入图片描述

方法一:链表从前遍历,数组从尾开始存储
方法二:将链表节点中的值存入栈中,在存入数组中

public int[] reversePrint(ListNode head) {
       ListNode p = head;
       int count = 0;
       while(p!=null){
           count++;
           p = p.next;
       }
       int[] ans = new int[count];
       int i = count - 1;
       while(head!=null){
           ans[i--] = head.val;
           head = head.next;
       }
       return ans;
    }

剑指 Offer 22. 链表中倒数第k个节点

在这里插入图片描述

快慢指针

public ListNode getKthFromEnd(ListNode head, int k) {
        ListNode quick = head;
        ListNode slow = head;
        for(int i = 0; i < k; i++){
            slow = slow.next;
        }
        while(slow != null){
            quick = quick.next;
            slow = slow.next;
        }
        return quick;
    }

138. 复制带随机指针的链表

在这里插入图片描述
在这里插入图片描述

class Solution {
    Map<Node, Node> map = new HashMap<Node, Node>();
    public Node copyRandomList(Node head) {
        if(head == null) return null;
        if(map.containsKey(head))
            return map.get(head);
        Node root = new Node(head.val);
        map.put(head, root);
        root.next = copyRandomList(head.next);
        root.random = copyRandomList(head.random);
        return root; 
    }  
}

剑指 Offer 24. 反转链表(常用)

在这里插入图片描述

public ListNode reverseList(ListNode head) {
        ListNode pre = null;
        ListNode cur = head;
        while(cur!= null){
            ListNode temp = cur.next;
            cur.next = pre;
            pre = cur;
            cur = temp;
        }
        return pre;
    }

剑指 Offer 18. 删除链表的节点

在这里插入图片描述

public ListNode deleteNode(ListNode head, int val) {
        if(head.val == val)
            return head.next;
        ListNode pre = head;
        ListNode nex = head.next;
        while(nex.val != val){
            pre = pre.next;
            nex = nex.next;
        }
        pre.next = nex.next;
        return head;
    }
public ListNode deleteNode(ListNode head, int val) {
        if(head == null) return null;
        ListNode p = head;
        
        if(p.val == val){
            p.val = p.next.val;
            p.next = p.next.next;
            return head;
        }
        ListNode current = p.next;
        while(current!= null && current.val!= val){
            p = current;
            current = p.next;
        }
        p.next = current.next;
        
        return head;
    }

剑指 Offer 52. 两个链表的第一个公共节点

在这里插入图片描述
在这里插入图片描述

 public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        ListNode temp = headA;
        int countA = 0;
        while(temp!= null){
            countA++;
            temp = temp.next;
        }
        temp = headB;
        int countB = 0;
        while(temp!=null){
            countB++;
            temp = temp.next;
        }

        ListNode tempA = countA < countB ? headA: headB;
        ListNode tempB = countA < countB ? headB : headA;

        int k = Math.abs(countB - countA);
        for(int i = 0; i < k; i++){
            tempB = tempB.next;
        }
        while(tempA!= null){
            if(tempA == tempB)
                return tempA;
            tempA = tempA.next;
            tempB = tempB.next;
        }
        return null;

    }

1721. 交换链表中的节点

在这里插入图片描述

public ListNode swapNodes(ListNode head, int k) {
        ListNode node1 = head;
        for(int i = 1; i < k; i++){
            node1 = node1.next;
        }

        ListNode node2 = head;
        ListNode quick = head;
        for(int i = 0; i < k; i++){   //先走k个
            quick = quick.next;
        }
        while(quick!= null){
            node2 = node2.next;
            quick = quick.next;
        }
        
        int temp = node1.val;
        node1.val = node2.val;
        node2.val = temp;
        return head;

    }

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

在这里插入图片描述

public ListNode swapPairs(ListNode head) {
        if(head == null || head.next == null)
            return head;
        ListNode temp = new ListNode();
        temp.next = head;
        ListNode cur = temp;  //前端联系
        while(cur.next!=null && cur.next.next != null){
            ListNode p1 = cur.next;
            ListNode p2 = cur.next.next;
            ListNode t = p2.next;   //后端联系联系

            //交换
            cur.next = p2;
            p2.next = p1;
            p1.next = t;
            //移动
            cur = p1;
        }
        return temp.next;
    }

面试题 02.05. 链表求和

在这里插入图片描述

public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        int carry = 0;
        ListNode head = new ListNode(0);
        ListNode temp = head;

        while(l1!=null && l2 != null){
            int val = (l1.val + l2.val + carry) % 10;
            carry = (l1.val + l2.val + carry)< 10? 0:1;
            temp.next = new ListNode(val);
            temp = temp.next;
            l1 = l1.next;
            l2 = l2.next;
        }
        while(l1!=null){
            int val = (l1.val + carry) % 10;
            carry = (l1.val + carry)< 10 ? 0:1;
            temp.next = new ListNode(val);
            temp = temp.next;
            l1 = l1.next;
        }

        while(l2!=null){
            int val = (l2.val + carry) % 10;
            carry = (l2.val + carry)< 10? 0:1;
            temp.next = new ListNode(val);
            temp = temp.next;
            l2 = l2.next;
        }
        if(carry > 0)
            temp.next = new ListNode(1);
        return head.next;
    }

725. 分隔链表

在这里插入图片描述

public ListNode[] splitListToParts(ListNode root, int k) {
        int length = 0;
        ListNode temp = root;
        while(temp != null){
            temp = temp.next;
            length++;
        }

        int avg = length / k;
        int remaind = length % k;
        ListNode[] ans = new ListNode[k];
        ListNode cur = root;

        for(int i = 0; i < k && cur != null; i++){
            ans[i] = cur;//一开始就有一个了
            int size = avg + (remaind-- > 0 ? 1 : 0);
            for(int j = 0; j < size - 1; j++){  //故这里减一
                cur = cur.next;
            }
            ListNode next = cur.next;
            cur.next = null;
            cur = next;
        }
        return ans;
    }
public ListNode sortList(ListNode head) {
        if(head==null||head.next==null)
            return head;
        ListNode slow = head;
        ListNode fast = head.next;
        while(fast!=null && fast.next != null){
            slow = slow.next;
            fast = fast.next.next;
        }
        ListNode temp = slow.next;
        slow.next = null;
        ListNode left = sortList(head);
        ListNode right = sortList(temp);
        ListNode h = new ListNode(0);
        ListNode cur = h;
        while(left != null && right != null){
            if(left.val < right.val){
                cur.next = left;
                left = left.next;
            } else{
                cur.next = right;
                right = right.next;
            }
            cur = cur.next;
        }
        cur.next = left!=null? left : right;
        return h.next;
    }

148. 排序链表(重要)

在这里插入图片描述

自顶向下:方法简单,容易实现

  • 快慢指针找到分割中点
  • 递归分割
  • 合并求解
public ListNode sortList(ListNode head) {
        if(head==null||head.next==null)
            return head;
        ListNode slow = head;
        ListNode fast = head.next;
        while(fast!=null && fast.next != null){
            slow = slow.next;
            fast = fast.next.next;
        }
        ListNode temp = slow.next;
        slow.next = null;
        ListNode left = sortList(head);//归并排序,先分后排序
        ListNode right = sortList(temp);
        
        ListNode h = new ListNode(0); //建立一个头节点方便求解
        ListNode cur = h;
        while(left != null && right != null){
            if(left.val < right.val){
                cur.next = left;
                left = left.next;
            } else{
                cur.next = right;
                right = right.next;
            }
            cur = cur.next;
        }
        cur.next = left!=null? left : right;
        return h.next;
    }

自底向上

public ListNode sortList(ListNode head) {
        if(head==null || head.next==null)
            return head;
        //统计链表长度
        int length = 0;
        ListNode curr = head;
        while(curr != null){
            curr = curr.next;
            length ++;
        }
        ListNode dummy = new ListNode(0, head);
        for(int sublen = 1; sublen < length; sublen <<= 1){
            ListNode prev = dummy;
            curr = dummy.next;
            //开始合并
            while(curr!=null){
                ListNode head1 = curr;
                //curr.next != null, 可以确保curr!=null,
                for(int i = 1; i < sublen && curr.next!=null; i++){
                    curr = curr.next;
                }
                //若curr.next == null , 则 curr!= null;	
                ListNode head2 = curr.next;
                curr.next = null;
                curr = head2;
               // curr等于上一个循环的curr.next, 主要是不确定上一个循环(可能是curr.next == null)是怎么结束的。加一个curr!=null确保
                for(int i = 1; i < sublen && curr!=null && curr.next!=null; i++){
                    curr = curr.next;
                }
                //保存下一个需要合并链表的开始
                ListNode next = null;
                if(curr != null){
                    next = curr.next;
                    curr.next = null;
                }
                ListNode merged = merge(head1,head2);
                prev.next = merged;
                //找到合并链表末尾
                while(prev.next != null){
                    prev = prev.next;
                }
                curr = next;
            }
        }
         return dummy.next;
    }
       

    private ListNode merge(ListNode head1, ListNode head2){
        ListNode dummy = new ListNode(0);
        ListNode curr = dummy, temp1 = head1, temp2 = head2;
        while(temp1 != null && temp2 != null){
            if(temp1.val <= temp2.val){
                curr.next = temp1;
                temp1 = temp1.next;
            } else {
                curr.next = temp2;
                temp2 = temp2.next;
            }
            curr = curr.next;
        }
        if(temp1 != null){
            curr.next = temp1;
        } else {
            curr.next = temp2;
        }
        return dummy.next;
    }

61. 旋转链表

在这里插入图片描述

public ListNode rotateRight(ListNode head, int k) {
        if(head == null || head.next == null)
            return head;
        ListNode slow = head;
        ListNode quick = head;
        int length = 0;
        ListNode curr = head;
        while(curr != null){
            curr = curr.next;
            length ++;
        }
        k = k % length;
        if(k == 0) return head;
        for(int i = 0; i < k; i++){
            quick = quick.next;
        }
        while(quick.next != null){
            quick = quick.next;
            slow = slow.next;
        }
        curr = slow.next;
        quick.next = head;
        slow.next = null;
        return curr;
    }

25. K 个一组翻转链表

在这里插入图片描述

先找到链表中有几个K长的链表,然后翻转操作,最后链接余下的链表长度

public ListNode reverseKGroup(ListNode head, int k) {
        if(head == null || head.next == null || k == 1)
            return head;
        int length = 0;
        ListNode curr = head;
        while(curr != null){
            length ++;
            curr = curr.next;
        }
        //链表中有几条完整的需要反转
        int circle = length / k;
        ListNode dummy = new ListNode(0, head);
        ListNode prev = dummy;
        curr = head;
        for(int i = 0; i < circle; i++){
            ListNode head1 = curr;
            for(int j = 1; j < k; j++){
                curr = curr.next;
            }
            ListNode temp = curr.next;
            curr.next = null;
            prev.next = reverse(head1);
            //翻转后curr就不是原来的curr了,找到末尾需要遍历 prev = curr是不对的。
            while(prev.next != null){
                prev = prev.next;
            }
            curr = temp;
        }
        //余数,没有排序的     
        if(curr != null){
            prev.next = curr;
        }
        return dummy.next;
    }

    private ListNode reverse(ListNode head){
        ListNode prev = null;
        ListNode curr = head;
        while(curr!=null){
            ListNode temp = curr.next;
            curr.next = prev;
            prev = curr;
            curr = temp;
        }
        return prev;

    }

92. 反转链表 II

在这里插入图片描述

public ListNode reverseBetween(ListNode head, int left, int right) {
        ListNode dummy = new ListNode(0,head);
        ListNode curr = dummy;
        for(int i = 1; i < left; i++){
            curr = curr.next;
        }
        //需要反转的前一个
        ListNode prev = curr;
        for(int i = 0; i < right - left + 1; i++){
            curr = curr.next;
        }
        ListNode temp = curr.next;
        curr.next = null;
        prev.next = reverse(prev.next);
        //找到末尾
        while(prev.next != null){
            prev = prev.next;
        }
        prev.next = temp;
        return dummy.next;

    }

    private ListNode reverse(ListNode head){
        ListNode prev = null;
        ListNode curr = head;
        while(curr != null){
            ListNode temp = curr.next;
            curr.next = prev;
            prev = curr;
            curr = temp;
        }
        return prev;
    }

206. 反转链表

public ListNode reverseList(ListNode head) {
        if(head == null || head.next == null)
            return head;
        ListNode prev = null;
        ListNode curr = head;
        while(curr!=null){
            ListNode temp = curr.next;
            curr.next = prev;
            prev = curr;
            curr = temp;
        }
        return prev;

    }

143. 重排链表

在这里插入图片描述

public void reorderList(ListNode head) {
        //找到中点,分成两个链,后面链反转后在将两个链合并
        if(head == null || head.next == null)
            return;
        ListNode slow = head;
        ListNode quick = head.next;
        while(quick != null && quick.next!=null){
            slow = slow.next;
            quick = quick.next.next;
        }

        ListNode head2 = slow.next;
        slow.next = null;
        head2 = reverse(head2);
        merge(head, head2);
    }
    private ListNode reverse(ListNode head){
        ListNode prev = null;
        ListNode curr = head;
        while(curr!=null){
            ListNode temp = curr.next;
            curr.next = prev;
            prev = curr;
            curr = temp;
        }
        return prev;
    }

    private ListNode merge(ListNode head1, ListNode head2){
        ListNode head = new ListNode(0);
        ListNode curr = head;
        while(head1!=null && head2 != null){
            curr.next = head1;
            ListNode temp = head1.next;
            curr = curr.next;
            curr.next = head2;
            head1 = temp;
            head2 = head2.next;
            curr = curr.next;
        }
        if(head1!=null){
            curr.next = head1;
        }
        return head.next;


    }

面试题 02.03. 删除中间节点

public void deleteNode(ListNode node) {
        //将后一个节点的值赋给当前节点,删除后一个节点
        node.val = node.next.val;
        node.next = node.next.next;
    }

138. 复制带随机指针的链表

在这里插入图片描述
在这里插入图片描述

使用hashMap映射节点

class Solution {
    Map<Node, Node> map = new HashMap<Node, Node>();
    public Node copyRandomList(Node head) {
        if(head == null) return null;
        if(map.containsKey(head))
            return map.get(head);
        Node root = new Node(head.val);
        map.put(head, root);
        root.next = copyRandomList(head.next);
        root.random = copyRandomList(head.random);
        return root; 
    }
    
}

109. 有序链表转换二叉搜索树

在这里插入图片描述

public TreeNode sortedListToBST(ListNode head) {
        if(head == null){
            return null;
        }
        return helper(head,null);
    }
    private TreeNode helper(ListNode head,ListNode tail){
        if(head == tail){
            return null;
        }
        ListNode fast = head;
        ListNode slow = head;
        while(fast != tail && fast.next != tail){
            fast = fast.next.next;
            slow = slow.next;
        }
        TreeNode root = new TreeNode(slow.val); //找到中间节点
        root.left = helper(head,slow);
        root.right = helper(slow.next,tail);
        return root;
    }

1290. 二进制链表转整数

在这里插入图片描述

	public int getDecimalValue(ListNode head) {
        if(head == null) return 0;
        int length = 0;
        ListNode curr = head;
        while(curr!=null){
            curr = curr.next;
            length++;
        }
        int res = 0;
        length--;
        curr = head;
        while(curr!=null){
            if(curr.val != 0){
                res += (curr.val << length);   
            }
            length--;
            curr = curr.next;
        }
        return res;
    }

445. 两数相加 II

在这里插入图片描述

  • 链表操作
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        l1 = reverse(l1);
        l2 = reverse(l2);
        ListNode dummy = new ListNode(0);
        ListNode curr = dummy;
        int carry = 0;
        while(l1!=null && l2 != null){
            int a = (l1.val + l2.val + carry) % 10;
            carry = (l1.val + l2.val + carry) / 10;
            curr.next = new ListNode(a);
            curr = curr.next;
            l1 = l1.next;
            l2 = l2.next;
        }
        while(l1 != null){
            int a = (l1.val + carry) % 10;
            carry = (l1.val + carry) / 10;
            curr.next = new ListNode(a);
            curr = curr.next;
            l1 = l1.next;
        } 
        while(l2 != null){
            int a = (l2.val + carry) % 10;
            carry = (l2.val + carry) / 10;
            curr.next = new ListNode(a);
            curr = curr.next;
            l2 = l2.next;
        }
        if(carry == 1){
            curr.next = new ListNode(1);
        }
        return reverse(dummy.next);

    }


    private ListNode reverse(ListNode head){
        ListNode prev = null;
        ListNode curr = head;
        while(curr!=null){
            ListNode temp = curr.next;
            curr.next = prev;
            prev = curr;
            curr = temp;
        }
        return prev;
    }
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        Deque<Integer> stack1 = new LinkedList<Integer>();
        Deque<Integer> stack2 = new LinkedList<Integer>();
        while (l1 != null) {
            stack1.push(l1.val);
            l1 = l1.next;
        }
        while (l2 != null) {
            stack2.push(l2.val);
            l2 = l2.next;
        }
        int carry = 0;
        ListNode ans = null;
        while (!stack1.isEmpty() || !stack2.isEmpty() || carry != 0) {
            int a = stack1.isEmpty() ? 0 : stack1.pop();
            int b = stack2.isEmpty() ? 0 : stack2.pop();
            int cur = a + b + carry;
            carry = cur / 10;
            cur %= 10;
            ListNode curnode = new ListNode(cur);
            curnode.next = ans;
            ans = curnode;
        }
        return ans;
    }

203. 移除链表元素

在这里插入图片描述

  • 只考虑删除链表节点
	public ListNode removeElements(ListNode head, int val) {
        ListNode dummy = new ListNode(0,head);
        ListNode curr = dummy;
       //创建头节点,这样第一个节点是null还是值等于val都可以考虑进去了。
        while(curr != null && curr.next!=null){
            if(curr.next.val == val){
                curr.next = curr.next.next;
            }else{
                curr = curr.next;
            }
        }
       //只考虑循环结束时,是curr.next == null 结束,curr里面还有值。
        if(curr != null && curr.val == val){
            curr = null;
        }
        return dummy.next;

    }
  • 有当前节点的上一个节点
public ListNode removeElements(ListNode head, int val) {
        ListNode dummy = new ListNode(0,head);
        ListNode curr = dummy.next;
        ListNode pre = dummy;
        while(curr != null ){
            if(curr.val == val){   
               pre.next = curr.next;
            } else {
                pre = curr;
            }
            curr = curr.next;                     
        }
        return dummy.next;
    }

1171. 从链表中删去总和值为零的连续节点(思路好)

在这里插入图片描述

public ListNode removeZeroSumSublists(ListNode head) {
        ListNode dummy = new ListNode(0);
        dummy.next = head;
        Map<Integer,ListNode> map = new HashMap<>();
        int sum  = 0;
        // 若同一和出现多次会覆盖,即记录该sum出现的最后一次节点
        for(ListNode d = dummy; d!=null; d = d.next){
            sum += d.val;
            map.put(sum, d);  //相同值,后面覆盖前面的
        }

        sum = 0;
         // 第二遍遍历 若当前节点处sum在下一处出现了则表明两结点之间所有节点和为0 直接删除区间所有节点
        for(ListNode d = dummy; d!=null; d= d.next){
            sum += d.val;
            d.next = map.get(sum).next;
        }
        return dummy.next;
    }

19. 删除链表的倒数第 N 个结点

在这里插入图片描述

public ListNode removeNthFromEnd(ListNode head, int n) {
       ListNode dummy = new ListNode(0,head);
       ListNode slow = dummy;
       ListNode quick = dummy;
       for(int i = 0; i < n; i++){
           quick = quick.next;
       }
       while(quick.next!=null){
           slow = slow.next;
           quick = quick.next;
       }
        slow.next = slow.next.next;
        return dummy.next;

    }

删除链表中重复元素

public ListNode deleteDuplicates(ListNode head) {
        ListNode dummy = new ListNode(Integer.MAX_VALUE, head);
        ListNode curr = dummy;
        ListNode next = curr.next;
        while(next != null){
            if(curr.val == next.val){
                curr.next = next.next;
                next = next.next;
            } else{
                curr = curr.next;
                next = next.next;
            }
        }
        return dummy.next; 
    }

82. 删除排序链表中的重复元素 II

在这里插入图片描述

public ListNode deleteDuplicates(ListNode head) {
        ListNode dummy = new ListNode(Integer.MAX_VALUE, head);
        ListNode pre = dummy;
        ListNode next = dummy.next;
        while(next != null){
            int temp = next.val;
            ListNode cur = next.next;
            boolean flag = true;
            while(cur != null){
                if(cur.val == temp){
                    cur = cur.next;
                    pre.next = cur;     //删除
                    flag = false;
                } else{
                    break;
                }
            }
            if(flag)  //有删除不移动,没删除就移动
                pre = next;
            next = cur;
        }
        return dummy.next; 
    }

83. 删除排序链表中的重复元素

在这里插入图片描述

public ListNode deleteDuplicates(ListNode head) {
        if(head == null || head.next == null) return head;
        ListNode curr = head;
        while(curr.next != null){
            if(curr.next.val == curr.val){
                curr.next = curr.next.next;
            } else{
                curr = curr.next;
            }
        }
        return head;
    }

面试题 02.01. 移除重复节点

题目同上

public ListNode removeDuplicateNodes(ListNode head) {
        if(head==null || head.next == null) return head;
        Map<Integer, ListNode> map = new HashMap<>();
        ListNode dummy = new ListNode(0,head);
        ListNode curr = dummy;
        while(curr.next!=null){
            if(map.containsKey(curr.next.val)){
                curr.next = curr.next.next;
            } else {
                map.put(curr.next.val, curr.next);
                curr = curr.next;
            }
        }
        return dummy.next;

    }

面试题 02.04. 分割链表

在这里插入图片描述

public ListNode partition(ListNode head, int x) {
        ListNode small = new ListNode(0);
        ListNode large = new ListNode(0);
        ListNode dummySmall = small;
        ListNode dummyLarge = large;
        ListNode curr = head;
        while(curr != null){
            if(curr.val < x){
                small.next = curr;
                curr = curr.next;
                small = small.next;
               
            } else{
                large.next = curr;
                curr = curr.next;
                large = large.next;
                
            }
        }
        small.next = dummyLarge.next;
        large.next = null;
        return dummySmall.next;
    }

面试题 02.06. 回文链表(重要)

在这里插入图片描述

  • 递归
class Solution {

    private ListNode frontPointer;
    public boolean isPalindrome(ListNode head) {
        frontPointer = head;
        return recursivelyCheck(head);
    }

    private boolean recursivelyCheck(ListNode curr) {
        if(curr != null){
            if(!recursivelyCheck(curr.next))  
                return false;
            if(curr.val != frontPointer.val) //从最后一个节点与第一个节点比较,然后
                return false;
            frontPointer = frontPointer.next;
        }
        return true;
    }
}
  • 快慢指针
public boolean isPalindrome(ListNode head) {
        if(head == null || head.next == null)
            return true;
        ListNode dummy = new ListNode(0,head);
        ListNode slow = dummy;
        ListNode quick = dummy.next;
        while(quick!=null && quick.next!=null){
            slow = slow.next;
            quick = quick.next.next;
        }
        ListNode head2 = null;
        if(quick==null){
            head2 = slow.next;
            slow.next = null;

        } else if(quick.next == null){
            head2 = slow.next.next;
        }
        head2 = reverse(head2);
        return compare(head, head2);
    }

    private ListNode reverse(ListNode head){
        ListNode pre = null;
        ListNode curr = head;
        while(curr != null){
            ListNode temp = curr.next;
            curr.next = pre;
            pre = curr;
            curr = temp;
        }
        return pre;
    }

    private boolean compare(ListNode head1, ListNode head2){
        ListNode cur1 = head1;
        ListNode cur2 = head2;
        while(cur1!= null && cur2!= null){
            if(cur1.val != cur2.val)
                return false;
            cur1 = cur1.next;
            cur2 = cur2.next;
        }
        return true;
    }

328. 奇偶链表

![在这里插入图片描述](https://img-blog.csdnimg.cn/20210518112344833.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0Rjd2po,size_16,color_FFFFFF,t_70)
public ListNode oddEvenList(ListNode head) {
        ListNode odd = new ListNode(0);
        ListNode dummyOdd = odd;
        ListNode even = new ListNode(0);
        ListNode dummyEven = even;
        int num = 1;
        ListNode cur = head;
        while(cur != null){
            ListNode next = cur.next;
            if(num % 2 == 1){
                odd.next = cur;
                odd = odd.next;
            } else {
                even.next = cur;
                even = even.next;
            }
            num++;
            cur.next = null;
            cur = next;
        }
        odd.next = dummyEven.next;
        return dummyOdd.next;
    }

1019. 链表中的下一个更大节点

在这里插入图片描述

public int[] nextLargerNodes(ListNode head) {
        //找到右边第一个比它大的值
        int len = 0;
        ListNode cur = head;
        while(cur != null){
            len ++;
            cur = cur.next;
        }

        int[] res = new int[len];
        int[] a = new int[len];
        cur = head;
        Stack<Integer> stack = new Stack<>();
        for(int i = 0; i < len; i++){
            a[i] = cur.val;
            cur = cur.next;
        }
        for(int i = 0; i < len; i++){
            while(!stack.isEmpty() && a[stack.peek()] < a[i]){
                res[stack.peek()] = a[i];
                stack.pop();
            }
            stack.push(i);
        }
        return res;
        
    }

876. 链表的中间结点

在这里插入图片描述

public ListNode middleNode(ListNode head) {
        ListNode dummy = new ListNode(0);
        dummy.next = head;
        ListNode slow = dummy;
        ListNode quick = dummy.next;
        while(quick!=null && quick.next != null){
            quick = quick.next.next;
            slow = slow.next;
        }
        return slow.next;

    }

21. 合并两个有序链表

在这里插入图片描述

public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        ListNode dummy = new ListNode(0);
        ListNode cur = dummy;
        while(l1 != null && l2 != null){
            if(l1.val <= l2.val){
                cur.next = l1;
                l1 = l1.next;
            } else {
                cur.next = l2;
                l2 = l2.next;
            }
            cur = cur.next;
        }
        if(l1 != null)
        {
            cur.next = l1;
        }
        if(l2 != null){
            cur.next = l2;
        }
        return dummy.next;
    }

23. 合并K个升序链表(递归,合并排序)

在这里插入图片描述

  • 常规方法
public ListNode mergeKLists(ListNode[] lists) {
        ListNode dummy = new ListNode(0);
        ListNode cur = dummy;
        if(lists == null)
            return null;
        if(lists.length == 1)
            return lists[0];
        for(int i = 0; i < lists.length - 1; i++){
            cur.next = merge(lists[i],lists[i+ 1]);
            lists[i + 1] = cur.next;
        }
        return dummy.next;
    }

    public ListNode merge(ListNode l1, ListNode l2) {
        ListNode dummy = new ListNode(0);
        ListNode cur = dummy;
        while(l1 != null && l2 != null){
            if(l1.val <= l2.val){
                cur.next = l1;
                l1 = l1.next;
            } else {
                cur.next = l2;
                l2 = l2.next;
            }
            cur = cur.next;
        }
        if(l1 != null)
        {
            cur.next = l1;
        }
        if(l2 != null){
            cur.next = l2;
        }
        return dummy.next;
    }
  • 优先队列
public ListNode mergeKLists(ListNode[] lists) {
        if (lists == null || lists.length == 0) return null;
        //优先队列
        PriorityQueue<ListNode> queue = new PriorityQueue<>(lists.length, new Comparator<ListNode>() {
            @Override
            public int compare(ListNode o1, ListNode o2) {
                return o1.val - o2.val;
            }
        });
        ListNode dummy = new ListNode(0);
        ListNode p = dummy;
        for (ListNode node : lists) {
            if (node != null) queue.add(node);
        }
        while (!queue.isEmpty()) {
            p.next = queue.poll();
            p = p.next;
            if (p.next != null) queue.add(p.next);
        }
        return dummy.next;
    }
  • 合并排序
public ListNode mergeKLists(ListNode[] lists) {
        if(lists == null || lists.length == 0) return null;
        return mergeSort(lists, 0, lists.length - 1);
    }
    
    public ListNode mergeSort(ListNode[] lists, int left, int right){
        if(left >= right) return lists[left];
        int mid = left + (right - left)/2;
        ListNode l1 = mergeSort(lists, left, mid);
        ListNode l2 = mergeSort(lists, mid + 1, right);
        return merge(l1, l2);
    }
    
    public ListNode merge(ListNode l1, ListNode l2){
        if(l1 == null) return l2;
        if(l2 == null) return l1;
        if(l1.val < l2.val){
            l1.next = merge(l1.next, l2);
            return l1;
        }
        l2.next = merge(l1, l2.next);
        return l2;
    }

1669. 合并两个链表

在这里插入图片描述

public ListNode mergeInBetween(ListNode list1, int a, int b, ListNode list2) {
        ListNode cur = list1;
        //找到第a - 1个节点
        for(int i = 1; i < a; i++){
            cur= cur.next;
        }
        ListNode head1 = cur;
        cur = list1;
        //找到第b个节点
        for(int i = 1; i <= b; i++){
            cur= cur.next;
        }
        //指向b+1个节点
        ListNode head2 = cur.next;
        head1.next = list2;
        cur = list2;
        while(cur.next != null){
            cur = cur.next;
        }
        cur.next = head2;
        return list1; 
    }

1367. 二叉树中的列表

在这里插入图片描述
在这里插入图片描述

	public boolean isSubPath(ListNode head, TreeNode root) {
        if(root == null)
            return false;
        return dfs(head, root) || isSubPath(head, root.left) || isSubPath(head, root.right);  //当前的要根+左子树+右子树
    }

    private boolean dfs(ListNode head, TreeNode root) {
        if(head == null)
            return true;
        if(root == null)
            return false;
        if(head.val != root.val) return false;
        return dfs(head.next, root.left) || dfs(head.next, root.right);
    }
  • 错误解法:没有考虑根节点,回不来了
class Solution {
    ListNode dummy = null;
    public boolean isSubPath(ListNode head, TreeNode root) {
        if(head == null)
            return true;
        dummy = head;
        return traver(head, root);
    }

    private boolean traver(ListNode head, TreeNode root) {
        if(head == null)
            return true;
        if(head != null)
            return false;
        if(head.val == root.val){
            return traver(head.next, root.left) || traver(head.next, root.right);
        } else
            return traver(dummy, root.left) || traver(dummy,root.right);
    }
}

面试题 02.08. 环路检测(重要)

在这里插入图片描述

public ListNode detectCycle(ListNode head) {
        Set<ListNode> set = new HashSet<>();
        ListNode cur  = head;
        while(cur != null){
            if(set.contains(cur)){
                return cur;
            } else{
                set.add(cur);
            }
            cur = cur.next;
        }
        return null;
    }

在这里插入图片描述
在这里插入图片描述

public ListNode detectCycle(ListNode head) {
        ListNode slow = head;
        ListNode quick = head;
        while(quick!= null && quick.next != null){
            quick = quick.next.next;
            slow = slow.next;
            if(slow == quick){
                while( head != slow){
                    head = head.next;
                    slow = slow.next;
                }
                return slow;
            }
        }
        return null;
    }

141. 环形链表

在这里插入图片描述

public boolean hasCycle(ListNode head) {
        ListNode quick = head;
        ListNode slow = head;
        while(quick != null && quick.next!= null){
            quick = quick.next.next;
            slow = slow.next;
            if(quick == slow)
                return true;
            
        }
        return false;
    }

面试题 02.02. 返回倒数第 k 个节点

在这里插入图片描述

public int kthToLast(ListNode head, int k) {
        ListNode slow = head;
        ListNode quick = head;
        //先走K个
        for(int i = 0; i < k; i++){
            quick = quick.next;
        }
        while(quick != null){
            slow = slow.next;
            quick = quick.next;
        }
        return slow.val;

    }

面试题 02.07. 链表相交

在这里插入图片描述

public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        ListNode cur = headA;
        int len1 = 0;
        while(cur != null){
            len1 ++;
            cur = cur.next;
        }
        cur = headB;
        int len2 = 0;
        while(cur != null){
            len2 ++;
            cur = cur.next;
        }
        ListNode h1 = len1 > len2 ? headA : headB;
        ListNode h2 = len1 <= len2 ? headA : headB;
        
        for(int i = 0; i < Math.abs(len1 - len2); i++){
            h1 = h1.next;
        }
        
        while(h1!= null){
            if(h1 == h2)
                return h1;
            h1 = h1.next;
            h2 = h2.next;
        }
        return null;
        
    }

237. 删除链表中的节点

在这里插入图片描述

public void deleteNode(ListNode node) {
        node.val = node.next.val;
        node.next = node.next.next;
    }

1670. 设计前中后队列

在这里插入图片描述

class ListNode{
    int val;
    ListNode next;
    ListNode(int val) {
        this.val = val;
    }
    ListNode(int val, ListNode next){
        this.val = val;
        this.next = next;
    }
}
class FrontMiddleBackQueue {
    ListNode dummy;
    ListNode tail;

    public FrontMiddleBackQueue() {
        dummy = new ListNode(0);
    }
    
    public void pushFront(int val) {
        ListNode node = new ListNode(val);
        ListNode temp = dummy.next;
        dummy.next = node;
        node.next = temp; 
    }
    
    public void pushMiddle(int val) {
        ListNode slow = dummy;
        ListNode quick = dummy.next;
        ListNode node = new ListNode(val);
        while(quick!= null && quick.next!= null){
            slow = slow.next;
            quick = quick.next.next;
        }
        ListNode temp = slow.next;
        slow.next = node;
        node.next = temp;
    }
    
    public void pushBack(int val) {
        ListNode cur = dummy;
        ListNode node = new ListNode(val);
        while(cur.next != null){
            cur = cur.next;
        }
        cur.next = node;

    }
    
    public int popFront() {
        if(dummy.next == null) return -1;
        ListNode node = dummy.next;
        dummy.next = dummy.next.next;
        return node.val;
    }
    
    public int popMiddle() {
        if(dummy.next == null) return -1;
        ListNode slow = dummy;
        ListNode quick = dummy.next;
        int temp = -1;
        while(quick!= null && quick.next!= null){
            slow = slow.next;
            quick = quick.next.next;
        }
        if(quick == null){
            temp = slow.val;
            slow.val = slow.next.val;
        } else{
            temp = slow.next.val;
        }
        slow.next = slow.next.next;
        return temp;


    }
    
    public int popBack() {
         if(dummy.next == null) return -1;
         ListNode cur = dummy;
         if(dummy.next.next == null) {
             cur = dummy.next;
             dummy.next = null;
             return cur.val;
         }      
         while(cur.next.next != null){
             cur = cur.next;
         }
         int n = cur.next.val;
         cur.next = null;
         return n;
    }
}

147. 对链表进行插入排序

在这里插入图片描述

public ListNode insertionSortList(ListNode head) {
        ListNode dummy = new ListNode(Integer.MIN_VALUE,head);
        ListNode cur = head;
        ListNode tail = dummy;
        while(cur != null){
            if(cur.val >= tail.val){
                tail = cur;
                cur = cur.next;
            }else {
                ListNode pre = dummy;
                ListNode now = dummy.next;  //细节。不能等于head
                while(now.val < cur.val){
                    pre = now;
                    now = now.next;
                }
                ListNode temp = cur.next;
                pre.next = cur;
                cur.next = now;
                tail.next = temp;
                cur = temp;
            }
        }
        return dummy.next;

    }

707. 设计链表

在这里插入图片描述

class ListNode{
    int val;
    ListNode next;
    ListNode(int val){
        this.val  = val;
    }

    ListNode(int val, ListNode next){
        this.val = val;
        this.next = next;
    }
}

class MyLinkedList {
    int len;
    ListNode dummy;

    /** Initialize your data structure here. */
    public MyLinkedList() {
        len = 0;
        dummy = new ListNode(0);
    }
    
    /** Get the value of the index-th node in the linked list. If the index is invalid, return -1. */
    public int get(int index) {
        if(index < 0 || index >= len)
            return -1;
        ListNode cur = dummy.next;
        for(int i = 0; i < index; i++){
            cur = cur.next;
        }
        if(cur != null)
            return cur.val;
        else 
            return -1;
    }
    
    /** Add a node of value val before the first element of the linked list. After the insertion, the new node will be the first node of the linked list. */
    public void addAtHead(int val) {
        ListNode temp = dummy.next;
        ListNode node = new ListNode(val);
        dummy.next = node;
        node.next = temp;
        len++;
    }
    
    /** Append a node of value val to the last element of the linked list. */
    public void addAtTail(int val) {
        ListNode node = new ListNode(val);
        ListNode cur = dummy;
        while(cur.next != null){
            cur = cur.next;
        }
        cur.next = node;
        len++;
    }
    
    /** Add a node of value val before the index-th node in the linked list. If index equals to the length of linked list, the node will be appended to the end of linked list. If index is greater than the length, the node will not be inserted. */
    public void addAtIndex(int index, int val) {
        if(index < 0){
            addAtHead(val);
        } else if(index >= len){
            addAtTail(val);
        } else{
            ListNode node = new ListNode(val);
            ListNode cur = dummy;
            for(int i = 0; i < index; i++){
                cur = cur.next;
            }
            ListNode temp = cur.next;
            cur.next = node;
            node.next = temp;
        }
        len++;

    }
    
    /** Delete the index-th node in the linked list, if the index is valid. */
    public void deleteAtIndex(int index) {
        if(0 <= index && index < len){
            ListNode cur = dummy;
            for(int i  = 0; i < index; i ++){
                cur = cur.next;
            }
            if(cur.next != null)
                cur.next = cur.next.next;       
        }
    }
}
class Solution {
  public Node flatten(Node head) {
    if (head == null) return head;

    Node pseudoHead = new Node(0, null, head, null);
    Node curr, prev = pseudoHead;

    Deque<Node> stack = new ArrayDeque<>();
    stack.push(head);

    while (!stack.isEmpty()) {
      curr = stack.pop();
      prev.next = curr;
      curr.prev = prev;

      if (curr.next != null) stack.push(curr.next);
      if (curr.child != null) {
        stack.push(curr.child);
        // don't forget to remove all child pointers.
        curr.child = null;
      }
      prev = curr;
    }
    // detach the pseudo node from the result
    pseudoHead.next.prev = null;
    return pseudoHead.next;
  }
}



链表总结

-「一个原则, 两种题型,三个注意,四个技巧」

一个原则

一个原则就是 画图
画图可以减少我们的认知负担,这其实和打草稿,备忘录道理是一样的,将存在脑子里的东西放到纸上。举一个不太恰当的例子就是你的脑子就是 CPU,脑子的记忆就是寄存器。寄存器的容量有限,我们需要把不那么频繁使用的东西放到内存,把寄存器用在真正该用的地方,这个内存就是纸或者电脑平板等一切你可以画图的东西。画的好看不好看都不重要,能看清就行了。用笔随便勾画一下, 能看出关系就够了。

两个考点

  • 指针的修改
    经典题目,链表反转
	public ListNode reverseList(ListNode head) {
        ListNode pre = null;
        ListNode cur = head;
        while(cur!= null){
       		 // 留下联系方式
            ListNode temp = cur.next;
            // 修改指针
            cur.next = pre;
            pre = cur;
            //继续下一个
            cur = temp;
        }
        return pre;
    }
  • 链表的拼接
    链表的价值就在于其「不必要求物理内存的连续性,以及对插入和删除的友好」

三个注意

  • 出现了环,造成死循环。
  • 分不清边界,导致边界条件出错。
  • 搞不懂递归怎么做

  • 题目就有可能环,让你判断是否有环,以及环的位置。
  • 题目链表没环,但是被你操作指针整出环了。
    这里我们只讨论第二种,而第一种可以用我们后面提到的「快慢指针算法」。

避免出现环最简单有效的措施就是画图,如果两个或者几个链表节点构成了环,通过图是很容易看出来的。因此一个简单的「实操技巧就是先画图,然后对指针的操作都反应在图中」。

但是链表那么长,我不可能全部画出来呀。其实完全不用,上面提到了链表是递归的数据结构, 很多链表问题天生具有递归性,比如反转链表,因此「仅仅画出一个子结构就可以了。「这个知识,我们放在后面的」前后序」部分讲解。

边界

  • 如果题目的头节点可能被移除,那么考虑使用虚拟节点,这样「头节点就变成了中间节点」,就不需要为头节点做特殊判断了。
  • 题目让你返回的不是原本的头节点,而是尾部节点或者其他中间节点,这个时候要注意指针的变化。

前后序

链表结构天生具有递归性,那么使用递归的解法或者递归的思维都会对我们解题有帮助。

前中后序实际上是指的当前节点相对子节点的处理顺序。如果先处理当前节点再处理子节点,那么就是前序。如果先处理左节点,再处理当前节点,最后处理右节点,就是中序遍历。后序遍历自然是最后处理当前节点了。

实际过程中,我们不会这么扣的这么死。比如:

def traverse(root):
    print('pre')
    traverse(root.left)
    traverse(root.righ)
    print('post')

如上代码,我们既在「进入左右节点前」有逻辑, 又在「退出左右节点之后」有逻辑。这算什么遍历方式呢?一般意义上,我习惯只看主逻辑的位置,如果你的主逻辑是在后面就是后序遍历,主逻辑在前面就是前序遍历。 这个不是重点,对我们解题帮助不大,对我们解题帮助大的是接下来要讲的内容。

绝大多数的题目都是单链表,而单链表只有一个后继指针。因此只有前序和后序,没有中序遍历
反转链表

  • 前序
def dfs(head, pre):
    if not head: return pre
    next = head.next
    # # 主逻辑(改变指针)在后面
    head.next = pre
    dfs(next, head)

dfs(head, None)
  • 后序
def dfs(head):
    if not head or not head.next: return head
    res = dfs(head.next)
    # 主逻辑(改变指针)在进入后面的节点的后面,也就是递归返回的过程会执行到
    head.next.next = head
    head.next = None

    return res

如果是前序遍历,那么你可以想象前面的链表都处理好了,怎么处理的不用管」。相应地「如果是后续遍历,那么你可以想象后面的链表都处理好了,怎么处理的不用管
在这里插入图片描述

def dfs(head, pre):
    if not head: return pre
    # 留下联系方式(由于后面的都没处理,因此可以通过 head.next 定位到下一个)
    next = head.next
    # 主逻辑(改变指针)在进入后面节点的前面(由于前面的都已经处理好了,因此不会有环)
    head.next = pre
    dfs(next, head)

dfs(head, None)

在这里插入图片描述
不难看出,我们可以通过 head.next 拿到下一个元素,然后将下一个元素的 next 指向自身来完成反转。
用代码表示就是: head.next.next = head:
在这里插入图片描述
画出图之后,是不是很容易看出图中有一个环? 现在知道画图的好处了吧?就是这么直观,当你很熟练了,就不需要画了,但是在此之前,请不要偷懒。
因此我们需要将 head.next 改为不会造成环的一个值,比如置空。
在这里插入图片描述

def dfs(head):
    if not head or not head.next: return head
    # 不需要留联系方式了,因为我们后面已经走过了,不需走了,现在我们要回去了。
    res = dfs(head.next)
    # 主逻辑(改变指针)在进入后面的节点的后面,也就是递归返回的过程会执行到
    head.next.next = head
    # 置空,防止环的产生
    head.next = None

    return res

「前序遍历很容易改造成迭代,因此推荐大家使用前序遍历」。我拿上面的迭代和这里的前序遍历给大家对比一下。
在这里插入图片描述
那么为什么「前序遍历很容易改造成迭代」呢?实际上,这句话我说的不准确,准确地说应该是「前序遍历容易改成不需要栈的递归,而后续遍历需要借助栈来完成」。

这里给大家插播一个写递归的技巧,那就是想象我们已经处理好了一部分数据,并把他们用手挡起来,但是还有一部分等待处理,接下来思考”如何根据已经处理的数据和当前的数据来推导还没有处理的数据“就行了。

四个技巧

虚拟头

  • Q1: 如下代码 ans.next 指向什么?
ans = ListNode(1)
ans.next = head
head = head.next
head = head.next

A1: 最开始的 head。

ans.next 指向什么取决于最后切断 ans.next 指向的地方在哪」。比如 Q1,ans.next 指向的是 head,我们假设其指向的内存编号为 9527。
在这里插入图片描述

之后执行 head = head.next (ans 和 head 被切断联系了),此时的内存图:
我们假设头节点的 next 指针指向的节点的内存地址为 10200
在这里插入图片描述
不难看出,ans 没变。

  • Q2:如下代码 ans.next 指向什么?
ans = ListNode(1)
head = ans
head.next = ListNode(3)
head.next = ListNode(4)

A2: ListNode(4)

对于第二个例子。一开始和上面例子一样,都是指向 9527。而后执行了:
区别是:这里的head不是真实的节点,而是一个指针,它指向ans,只要ans.next(head.next)指向谁就是指向谁,一旦head = 其他节点,这时候ans就和head没有关系,ans.next 就是最后一次head.next指向的值。

head.next = ListNode(3)
head.next = ListNode(4)
  • Q3: 如下代码 ans.next 指向什么?
ans = ListNode(1)
head = ans
head.next = ListNode(3)
head = ListNode(2)
head.next = ListNode(4)

在指针head改变之前最后一次是指向了ListNode(3),所以ans.next = ListNode(3);改变后的head就在和ans没关系了。

指向了 head = ListNode(2) 之后, head 和 ans 的关系就被切断了,「当前以及之后所有的 head 操作都不会影响到 ans」,因此 ans 还指向被切断前的节点,因此 ans.next 输出的是 ListNode(3)。

  • 使用头节点的好处
  1. 将头节点变成中间节点,简化判断。
  2. 通过在合适的时候断开链接,返回链表的中间节点。

快慢指针

判断链表是否有环,以及环的入口都是使用快慢指针即可解决。
除了这个,求链表的交点也是快慢指针,算法也是类似的。

另外由于链表不支持随机访问,因此如果想要获取数组中间项和倒数第几项等特定元素就需要一些特殊的手段,而这个手段就是快慢指针。比如要找链表中间项就「搞两个指针,一个大步走(一次走两步),一个小步走(一次走一步)」,这样快指针走到头,慢指针刚好在中间。 如果要求链表倒数第 2 个,那就「让快指针先走一步,慢指针再走」,这样快指针走到头,慢指针刚好在倒数第二个。

穿针引线

25. K 个一组翻转链表61. 旋转链表92. 反转链表 II
这个方法通常不是最优解,但是好理解,方便书写,不易出错,推荐新手用。
还是以反转链表为例,只不过这次是反转链表的中间一部分,那我们该怎么做?
在这里插入图片描述
反转前面我们已经讲过了,于是我假设链表已经反转好了,那么如何将反转好的链表拼后去呢?
在这里插入图片描述
我们想要的效果是这样的:
在这里插入图片描述
那怎么达到图上的效果呢?我的做法是从做到右给断点编号。如图有两个断点,共涉及到四个节点。于是我给它们依次编号为 a,b,c,d。
其实 a,d 分别是需要反转的链表部分的前驱和后继(不参与反转),而 b 和 c 是需要反转的部分的头和尾(参与反转)。
在这里插入图片描述
因此除了 cur, 多用两个指针 pre 和 next 即可找到 a,b,c,d。
找到后就简单了,直接「穿针引线」。

a.next = c
b.next = d
  • 先穿再排后判空:
    链表反转
cur = head
pre = None
while cur != tail:
    # 留下联系方式
    next = cur.next
    # 修改指针
    cur.next = pre
    # 继续往下走
    pre = cur
    cur = next
return pre

什么时候需要判断 next 是否存在,上面两行代码先写哪个呢?
是这样?

    next = cur.next
    cur.next = pre

还是这样?

    cur.next = pre
    next = cur.next
  • 先穿
    我给你的建议是:先穿。这里的穿是修改指针,包括反转链表的修改指针和穿针引线的修改指针。「先别管顺序,先穿」。
  • 再排
    穿完之后,代码的总数已经确定了,无非就是排列组合让代码没有 bug。
    因此第二步考虑顺序,那上面的两行代码哪个在前?应该是先 next = cur.next ,原因在于后一条语句执行后 cur.next 就变了。由于上面代码的作用是反转,那么其实经过 cur.next = pre 之后链表就断开了,后面的都访问不到了,也就是说此时你「只能返回头节点这一个节点」。
    实际上,有假如有十行「穿」的代码,我们很多时候没有必要全考虑。我们「需要考虑的仅仅是被改变 next 指针的部分」。比如 cur.next = pre 的 cur 被改了 next。因此下面用到了 cur.next 的地方就要考虑放哪。其他代码不需要考虑。
  • 后判空
    和上面的原则类似,穿完之后,代码的总数已经确定了,无非就是看看哪行代码会空指针异常。
    和上面的技巧一样,我们很多时候没有必要全考虑。我们「需要考虑的仅仅是被改变 next 指针的部分」

比如这样的代码

while cur:
    cur = cur.next

我们考虑 cur 是否为空呢? 很明显不可能,因为 while 条件保证了,因此不需判空。
那如何是这样的代码呢?

while cur:
    next = cur.next
    n_next = next.next

如上代码有两个 next,第一个不用判空,上面已经讲了。而第二个是需要的,因为 next 可能是 null。如果 next 是 null ,就会引发空指针异常。因此需要修改为类似这样的代码:

while cur:
    next = cur.next
    if not next: break
    n_next = next.next


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值