文章目录
链表
链表的概念概念
- 链表是一种常见的链式结构(linked list)
- 链表由节点链接而成
- 每个链表的节点包含数据成员和指向下一个节点的指针
不同的链表类型
单链表(linked list)
-
特点:
- 1、可以方便地追加元素到链表尾部,O(1)
- 2、不支持随机下标访问,查找元素地时间复杂度是O(n),需要从头开始一个个查找
-
class Node: def __init__(self, value, next=None): self.value = value self.next = next
双链表(double linked list)
-
特点:
- 1、可以给单链表再加一个指针(节点前后都有一个指针,左指针和右指针),指向前一个节点
- 2、双链表可以支持反向遍历
- 3、知道了双链表的一个节点后,可以将它的左指针或右指针指向另一个节点,即将两个节点串起来,从而实现**O(1)**插入,同理删除也是O(1)
- 4、双链表还可以首位指针相连形成一个循环双端链表(至少两个节点)
- 5、双链表可以高效地往两头增加或删除元素
-
class Node: def __init__(self, value, prev=None, next=None): self.value, self.prev, self,next = value, prev, next
链表练习
如何将一个list构造一个链表并编写一个打印单链表的函数
-
class LinkedListNode(): def __init__(self, value, next=None): self.value = value self.next = next def gen_linked_list(nums): if not nums: return None head = LinkedListNode(nums[0]) cur = head for i in range(1, len(nums)): node = LinkedListNode(nums[i]) cur.next = node cur = node return head def print_linked_list(head): cur = head while cur: print('{}->'.format(cur.value), end='') cur = cur.next print('nil') if __name__ == "__main__": nums = [1,2,3,4] head = gen_linked_list(nums) print_linked_list(head)
反转链表
-
解法:
-
第一种方法利用指针迭代,比较好理解
-
第二种使用递归,找出最后一个节点,然后递归实现最后一个节点需要做的事情
-
class Solution(object): def reverseList(self, head): """ :type head: ListNode :rtype: ListNode """ # 迭代 时间复杂度:O(n),空间复杂度:O(1) # pre = None # cur = head # while cur: # nextnode = cur.next # cur.next = pre # pre = cur # cur = nextnode # return pre # 递归 时间复杂度:O(n),空间复杂度:O(1) if not (head and head.next): return head newhead = self.reverseList(head.next) head.next.next = head head.next = None return newhead # when-changed -r -v -1 'filepath' pytest -s 'filepath' def test_reverselist(): L = [1,2,3,4,5] head = gen_linked_list(L) print() print_linked_list(head) pre = Solution().reverseList(head) print_linked_list(pre)
-
合并两个排序的链表
-
解法:
-
纸上做草稿,使用指针完成
-
输入两个递增排序的链表,合并这两个链表并使新链表中的节点仍然是递增排序的。 示例1: 输入:1->2->4, 1->3->4 输出:1->1->2->3->4->4
-
# Definition for singly-linked list. class ListNode(object): def __init__(self, x): self.val = x self.next = None class Solution(object): def mergeTwoLists(self, l1, l2): """ :type l1: ListNode :type l2: ListNode :rtype: ListNode """ pre = ListNode(0) cur = pre while l1 and l2: if l1.val <= l2.val: cur.next = l1 l1 = l1.next cur = cur.next else: cur.next = l2 l2 = l2.next cur = cur.next cur.next = l1 or l2 return pre.next def test_mergeTwoLists(): l1 = gen_linked_list([1,2,4]) l2 = gen_linked_list([1,3,4]) s = Solution().mergeTwoLists(l1, l2) print_linked_list(s) def gen_linked_list(nums): if not nums: return None head = ListNode(nums[0]) cur = head for i in range(1, len(nums)): node = ListNode(nums[i]) cur.next = node cur = node return head def print_linked_list(head): cur = head while cur: print('{}->'.format(cur.val), end='') cur = cur.next print('nil')
-
相交链表
-
解法:
-
第一种方式,将长链表砍掉一部分使得它的长度与短链表一样长,然后判断
-
第二种方式,将两个链表相交即长度都相等了,再判断
-
编写一个程序,找到两个单链表相交的起始节点。
-
-
class ListNode(object): def __init__(self, x): self.val = x self.next = None class Solution(object): def getIntersectionNode(self, headA, headB): """ :type head1, head1: ListNode :rtype: ListNode """ # 第一种方式,将长链表砍掉一部分使得它的长度与短链表一样长 # if headA is None or headB is None: # return None # curA = headA # lenA = 0 # while curA: # lenA += 1 # curA = curA.next # curB = headB # lenB = 0 # while curB: # lenB += 1 # curB = curB.next # ldiff = abs(lenA-lenB) # if lenA > lenB: # for _ in range(ldiff): # headA = headA.next # else: # for _ in range(ldiff): # headB = headB.next # while headA and headB: # if headA == headB: # # print(headA,headB) # return headA # headA = headA.next # headB = headB.next # return None # 第二种方式,将两个链表相交即长度都相等了,再判断 ha, hb = headA, headB while ha != hb: ha = ha.next if ha else headB hb = hb.next if hb else headA return ha
-
环形链表
-
思路:
-
1、开辟一个新的内存空间即创建一个set(集合),利用集合元素不重复的特性
-
2、快慢指针,若闭环,快慢指针一定会相遇
-
给定一个链表,判断链表中是否有环。 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。
-
-
# Definition for singly-linked list. class ListNode(object): def __init__(self, x): self.val = x self.next = None class Solution(object): def hasCycle(self, head): """ :type head: ListNode :rtype: bool """ # 第一种使用hash表存储(集合,根据元素不重复的特性) # 时间复杂度O(n),空间复杂度O(n) # hash = {} # cur = head # while cur: # if hash.get(cur.next) is not None: # return True # hash[cur] = 1 # cur = cur.next # return False # 利用快慢指针 # 时间复杂度O(n),空间复杂度O(1) slow, fast = head, head while fast and fast.next: slow = slow.next fast = fast.next.next if slow == fast: return True return False
-
两数相加
-
思路:
-
1、竖式计算,定义多几个变量(指针)进行操作,会方便很多,重点在于获取值的方式,%10为获取个位,//10获取进位
-
2、使用递归的方式
-
给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。 如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。 您可以假设除了数字 0 之外,这两个数都不会以 0 开头。 示例: 输入:(2 -> 4 -> 3) + (5 -> 6 -> 4) 输出:7 -> 0 -> 8 原因:342 + 465 = 807
-
class ListNode(object): def __init__(self, x): self.val = x self.next = None class Solution: # 迭代的方式 def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode: # 迭代的方式,创建了新的链表,空间复杂度O(n),时间复杂度O(n) pre = cur = ListNode(None) # pre变量用于返回,cur用于指向新创建的节点 s = 0 # 中间暂存变量 while l1 or l2 or s: # if l1 == None: # l1 = ListNode(0) # if l2 == None: # l2 = ListNode(0) s += (l1.val if l1 else 0) + (l2.val if l2 else 0) # 注意是+=,存储l1和l2节点的值 cur.next = ListNode(s%10) # 新节点赋值 %10取个位 s = s//10 # 取进位的值 cur = cur.next # 使指向新节点的指针向前指 l1 = l1.next if l1 else None # l1向前走 l2 = l2.next if l2 else None # l2向前走 return pre.next # 返回新节点的首节点 # 递归的方式,添加参数carry # class Solution: # def addTwoNumbers(self, l1: ListNode, l2: ListNode, carry=0) -> ListNode: # if l1==None and l2==None and carry==0: # return None # if l1==None and l2==None and carry==1 : # return ListNode(1) # if l1==None : # l1 = ListNode(0) # if l2==None : # l2 = ListNode(0) # l1.val, carry = (l1.val+l2.val+carry)%10, (l1.val+l2.val+carry)//10 # l1.next = self.addTwoNumbers(l1.next, l2.next, carry) # return l1 def test_addTwoNumbers(): l1 = gen_linked_list([2,4,3,2]) l2 = gen_linked_list([5,6,4]) s = Solution().addTwoNumbers(l1,l2) print_linked_list(s) def gen_linked_list(nums): if not nums: return None head = ListNode(nums[0]) cur = head for i in range(1, len(nums)): node = ListNode(nums[i]) cur.next = node cur = node return head def print_linked_list(head): cur = head while cur: print('{}->'.format(cur.val), end='') cur = cur.next print('nil')
-