剑指offer-链表

剑指 Offer 06. 从尾到头打印链表 - 力扣(LeetCode) (leetcode-cn.com)

  • 思路:翻转链表。

  • 代码:

    class Solution {
        public int[] reversePrint(ListNode head) {
            if(head == null){
                return new int[0];
            }
            ListNode p = head;
            int len = 0;
            while(p != null){
                len++;
                p = p.next;
            }
            int[] res = new int[len];
            ListNode reverseHead = reverse(head);
            p = reverseHead;
            int idx = 0;
            while(p != null){
                res[idx++] = p.val;
                p = p.next;
            }
            return res;
        }
        public ListNode reverse(ListNode head){
            if(head == null){
                return null;
            }
            ListNode p = head, q = head.next, h = null;
            while(q != null){
                h = q.next;
                q.next = p;
                p = q;
                q = h;
            }
            head.next = null;
            head = p;
            return head;
        }
    }
    

剑指 Offer 22. 链表中倒数第k个节点 - 力扣(LeetCode) (leetcode-cn.com)

  • 思路:依然是翻转链表。

  • 代码:

    class Solution {
        public ListNode getKthFromEnd(ListNode head, int k) {
            ListNode dummy = new ListNode();
            ListNode reverseNode = reverse(head);
            dummy.next = reverseNode;
            ListNode p = dummy;
            while(k > 0){
                p = p.next;
                k--;
            }
            p.next = null;
            return reverse(dummy.next);
    
        }
        private ListNode reverse(ListNode head){
            if(head == null || head.next == null){
                return head;
            }
            ListNode p = head, q = head.next, h = null;
            while(q != null){
                h = q.next;
                q.next = p;
                p = q;
                q = h;
            }
            head.next = null;
            head = p;
            return head;
        }
    }
    

剑指 Offer 25. 合并两个排序的链表 - 力扣(LeetCode) (leetcode-cn.com)

  • 思路:记录设置虚拟头结点。

  • 代码:

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

剑指 Offer 24. 反转链表 - 力扣(LeetCode) (leetcode-cn.com)

  • 思路:三个工作指针来工作,分别之前当前,下一个和下下一个,每次要保存结点信息,然后指针下移。

  • 代码:

    class Solution {
        public ListNode reverseList(ListNode head) {
            if(head == null || head.next == null){
                return head;
            }
            ListNode p = head, q = head.next, h = null;
            while(q != null){
                h = q.next;
                q.next = p;
                p = q;
                q = h;
            }
            head.next = null;
            head = p;
            return head;
        }
    }
    

剑指 Offer 18. 删除链表的节点 - 力扣(LeetCode) (leetcode-cn.com)

  • 思路:根据值找。删除的最好使用虚拟头结点。

  • 代码:

    class Solution {
        public ListNode deleteNode(ListNode head, int val) {
            if(head == null){
                return head;
            }
            ListNode dummy = new ListNode();
            dummy.next = head;
            ListNode pre = dummy, p = dummy.next;
            while(p.val != val){
                pre = p;
                p = p.next;
            }
            pre.next = p.next;
            return dummy.next;
        }
    }
    
    

剑指 Offer 35. 复杂链表的复制 - 力扣(LeetCode) (leetcode-cn.com)

  • 思路:

    • 先进行判空处理,这里值需要判断当前是否为空,不需要判断下一个为空。
    • 从next方向进行copy,等到在next方向上的链表。
    • 然后再从random方向进行复制,此时的情况是1->1’->2->2’,所以这个时候,要读copy的链表进行赋值的时候,只需要看原链表当前结点有没有random域。有就赋给random.next,没有就是空。
    • 然后再做分割
      • 分割也是从next方向进行分割
    class Solution {
        public Node copyRandomList(Node head) {
            if(head == null){
                return head;
            }
            Node p = head;
            Node nextNode = null;
            while(p != null){
                nextNode = p.next;
                Node s = new Node(p.val);
                s.next = p.next;
                p.next = s;
                p = nextNode;
            }
            p = head;
            Node copy = null;
            while(p != null){
                nextNode = p.next.next;
                copy = p.next;
                if(p.random != null){
                    copy.random = p.random.next;
                }else {
                    copy.random = null;
                }
                p = nextNode;
            }
            //分割
            Node res = head.next;
            p = head;
            while(p != null){
                nextNode = p.next.next;
                copy = p.next;
                p.next = nextNode;
                if(nextNode != null){
                    copy.next = nextNode.next;
                }else {
                    copy.next = null;
                }
                p = nextNode;
            }
            return res;
        }
    }
    
  • 代码的细节:

    • 在next方向进行copy的时候,要先保存下一个节点,不能在最后直接进行.next.next,因为这样可能.next为空。每次完成copy的时候,就把保存的节点给当前工作节点。
    • 在random方向上进行copy的时候,因为存在copy节点,所以每次保存的时候要存取.next.next,不会存在为空的情况。同样把保存结点给工作节点。
    • 分割的时候,设置一个结果res,用来返回
      • 将工作指针指向头,返回结果指向第一个节点的下一个。
      • 在循环体内,先保存原链表的节点.next.next。记录复制的节点.next
      • 把原来的链表进行连接,p.next=.next.next。
      • 复制的节点如何连接?
        • 首先判断.next.next存不存在,存在就连,不存在就不连。

剑指 Offer 36. 二叉搜索树与双向链表 - 力扣(LeetCode) (leetcode-cn.com)

  • 思路:

    • 使用dfs,根据结结果看是一个中序遍历,使用中序存储在一个list中。
    • 然后判断大小,为空就返回空。
    • 不为空,先取出第一个节点,作为头结点,然后设置pre=head,cur=null,循环读取list中的节点,left就是比他小的,right就是比他大的。
    • 最后的时候要处理最后一个节点和头结点的关系。
    class Solution {
        List<Node> res = new LinkedList<>();
        public Node treeToDoublyList(Node root) {
            dfs(root);
            int size = res.size();
            if(size == 0){
                return null;
            }
            Node head = res.get(0);
            Node pre = head;
            Node cur = null;
            for(int i = 1; i < size; i++){
                cur = res.get(i);
                pre.right = cur;
                cur.left = pre;
                pre = cur;
            }
            pre.right = head;
            head.left = pre;
            return head;
    
        }
        public void dfs(Node root){
            if(root == null){
                return;
            }
            dfs(root.left);
            res.add(root);
            dfs(root.right);
        }
    }
    

剑指 Offer 52. 两个链表的第一个公共节点 - 力扣(LeetCode) (leetcode-cn.com)

  • 思路:计算两个链表的差值,长的链表先走差值步,然后再一起走。

  • 代码:

    public class Solution {
        public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
            if(headA == null || headB == null){
                return null;
            }
            ListNode p = headA, q = headB;
            int n1 = 0, n2 = 0;
            while(p != null){
                n1++;
                p = p.next;
            }
            while(q != null){
                n2++;
                q = q.next;
            }
            ListNode longer = null, shorter = null;
            if(n1 > n2){
                longer = headA;
                shorter = headB;
            }else {
                longer = headB;
                shorter = headA;
            }
            int dif = n1 > n2 ? n1 - n2 : n2 - n1;
            p = headA;
            q = headB;
            while(dif > 0){
                longer = longer.next;
                dif--;
            }
            while(longer != shorter){
                longer = longer.next;
                shorter = shorter.next;
            }
            return longer;
        }
    }
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值