剑指offer链表篇

43 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第24天,点击查看活动详情

大家好,我是bug郭,一名双非科班的在校大学生。对C/JAVA、数据结构、Spring系列框架、Linux及MySql、算法等领域感兴趣,喜欢将所学知识写成博客记录下来。 希望该文章对你有所帮助!如果有错误请大佬们指正!共同学习交流

作者简介:

从尾到头打印链表

题目链接:从头到尾打印链表信息 **** 题目分析:

  • 直接遍历借助栈数据结构先进先出

题目解答:

空间/时间复杂度:O(n)

java

import java.util.*;
public class Solution {
    public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
        ArrayList<Integer> res = new ArrayList<>();
        Stack<Integer> stack = new Stack<>();
        if(listNode==null||listNode.next==null) return res;
        while(listNode!=null){ //栈保存
            stack.add(listNode.val);
            listNode = listNode.next;
        }
        while(!stack.isEmpty()){//然后出栈!
            res.add(stack.pop());
        }
        return res;
    }
}

python

class Solution:
    def printListFromTailToHead(self , listNode: ListNode) -> List[int]:
        # write code here
        res = []
        cur = listNode
        while cur != None:
            res.insert(0,cur.val)
            cur = cur.next
        return res
  • 我们可以这里关键点就是需要知道当前节点上一个节点的位置!
  • 这里我们可以通过递归,可以达到和栈一样的效果!

复杂度和上面一样,就是通过递归栈代替了我们自定义的栈!

java

import java.util.ArrayList;
public class Solution {
     ArrayList<Integer> res;
    public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
        //递归!!!
       res = new ArrayList<>();
        dfs(listNode);
        return res;
    }
    public void dfs(ListNode cur){
        if(cur==null) return;
        dfs(cur.next);//找尾!
        res.add(cur.val);
    }

}

python

import sys
sys.setrecursionlimit(100000) # 设置递归深度!

class Solution:
    def dfs(self,cur: ListNode, res: List[int]):
        if cur is None:
            return
        self.dfs(cur.next,res)
        res.append(cur.val)

    def printListFromTailToHead(self, listNode: ListNode) -> List[int]:
        # write code here
        res = []
        self.dfs(listNode, res)
        return res

反转链表

题目链接:反转链表 在这里插入图片描述 题目分析:

  • 这里空间复杂度为O(1)那就要求原地反转链表!
  • 显然这里不能借助其他数据结果,或者递归!
  • 所以我们可以通过多个指针记录反转节点位置进行操作

在这里插入图片描述

java

public class Solution {
    public ListNode ReverseList(ListNode head) {
        ListNode pre = null,cur = head,end = head;
        while(end!=null){
            end = cur.next;
            cur.next = pre;
            pre = cur;
            cur = end;
        }
        return pre;
    }
}

python

class Solution:
    def ReverseList(self , head: ListNode) -> ListNode:
        # write code here
        pre,cur,end = None,head,head
        while cur != None:
            end = cur.next
            cur.next = pre
            pre = cur
            cur = end
        return pre

合并两个排序的链表

题目链接:合并两个排序的链表 在这里插入图片描述

题目分析:

  • 这里是2个排序链表!
  • 我们可以创建一个新链表,然后遍历这2个链表,比较2个链表中的元素!
  • 较小值就尾插到新链表!
  • 返回新链表即可
  • 注意比较时有可能有链表已经为空,所以直接尾插另一个链表即可!

java

public class Solution {
    public ListNode Merge(ListNode list1,ListNode list2) {
        ListNode cur1 = list1,cur2 = list2;
        ListNode head = new ListNode(-1);
        ListNode cur = head;
        while(cur1!=null&&cur2!=null){
            if(cur1.val<cur2.val){
                cur.next = cur1;
                cur1 = cur1.next; 
            }else{
                cur.next = cur2;
                cur2 = cur2.next;
            }
            cur = cur.next;
        }
		if(cur1!=null){
			cur.next = cur1;
		}
		if(cur2!=null){
			cur.next = cur2;
		}
		return cur;
}

python


class Solution:
    def Merge(self , pHead1: ListNode, pHead2: ListNode) -> ListNode:
        # write code here
        dummy = ListNode(-1)
        cur = dummy
        while pHead1 and pHead2:
            if pHead1.val<pHead2.val:
                cur.next = pHead1
                pHead1 = pHead1.next
            else:
                cur.next = pHead2
                pHead2 = pHead2.next
            cur = cur.next
 		if pHead1:
            cur.next = pHead1
        if pHead2:
            cur.next = pHead2
        return dummy.next

两个链表的第一个公共结点

题目链接: 两个链表的第一个公共结点 在这里插入图片描述

题目分析:

  • 可以直接先遍历一遍计算2个链表长度的差值,然后再让一个链表遍历到差值位,然后同时遍历,比较节点是否相同!!!
  • 通过两个指针速度相同,走过的路程相同必会相遇!
  • cur1 走完 L1,cur1指向 L2,cur2走完L2,指向L1!

差值法 java

//先计算长度差,然后让一个指针先走差值单位!
public class Solution {
    public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
            ListNode cur1 = pHead1;
            ListNode cur2 = pHead2;
        int size1 = 0;
        int size2 = 0;
        while(cur1!=null){
            cur1 = cur1.next;
            size1++;
        }
        while(cur2!=null){
            cur2 = cur2.next;
            size2++;
        }
        if(size1>size2){
            int len = size1 - size2;
            while(len-->0){
                pHead1 = pHead1.next;
            }
        }else{
             int len = size2 - size1;
            while(len-->0){
                pHead2 = pHead2.next;
            }
        }
         
        while(pHead1!=null){
            if(pHead1.val==pHead2.val){
                return pHead1;
            }
            pHead1 = pHead1.next;
            pHead2 = pHead2.next;
        }
        return null;
    }
}

python

class Solution:
    def FindFirstCommonNode(self , pHead1 , pHead2 ):
        # write code here
        len1=len2 = 0
        cur1,cur2 = pHead1,pHead2
        while cur1:
            len1+=1
            cur1 = cur1.next
        while cur2:
            len2 +=1
            cur2 = cur2.next
        # 这里还要判断那个链表的长度更长...
        # 我们默认设置为cur1链表更长!
        size = 0
        if len1>len2:
            size = len1 - len2
            cur1 = pHead1
            cur2 = pHead2
        else:
            size = len2 - len1
            cur1 = pHead2
            cur2 = pHead1
        while size:
            cur1 = cur1.next
            size -= 1
        #遍历2个链表比较!
        while cur1 and cur2:
            if cur1 == cur2:
                return cur1
            cur1 = cur1.next
            cur2 = cur2.next
        return cur1

相同路程法 操作如图所示

36

public class Solution {
    public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
            //定义2个指针! 
            // cur1 走完 L1,又从 L2开始!
            // cur2 走完 L2,又从 L1开始!
            // 这里两个指针速度相同,走过的长度相等,如果有相同节点肯定相遇!
        ListNode cur1 = pHead1;
        ListNode cur2 = pHead2;
        while(cur1!=cur2){//不存在公共节点,两个指针会来到null相等退出循环!
            cur1 = (cur1==null) ? pHead2 : cur1.next;
            cur2 = (cur2 == null) ? pHead1 : cur2.next;
        }
        return cur1;
    }
}

链表中环的入口结点

链表中环的入口结点

image-20220621092004731

image-20220621092032662

/*
 public class ListNode {
    int val;
    ListNode next = null;
​
    ListNode(int val) {
        this.val = val;
    }
}
*/
public class Solution {
​
    public ListNode EntryNodeOfLoop(ListNode pHead) {
        //快慢指针,利用链表头到入口距离 = 相遇点到入口距离!
        //所以当两个节点相遇后再走L距离就是入口位置!
        //相遇后让其中一个指针从链头开始走L,一个从相遇点开始!
        ListNode slow = pHead,fast = pHead;
        while(fast!=null&&fast.next!=null){//注意判断条件!!!!
            fast = fast.next.next;
            slow = slow.next;
            if(fast==slow){
                //相遇!
                //让slow从头结点开始!
                slow = pHead;
                while(fast!=slow){
                    slow = slow.next;
                    fast = fast.next;
                }
                return fast;
            }
        }
        return null;
    }
}