LeetCode刷题总结-链表
一、链表
链表分为单向链表、单向循环链表和双向链表,一下以单向链表为例实现单向链表的节点实现和单链表的基本操作。
单向链表
单向链表也叫单链表,是链表中最简单的一种形式,它的每个节点包含两个域,一个信息域(元素域)和一个链接域。这个链接指向链表中的下一个节点,而最后一个节点的链接域则指向一个空值。
- 表元素域elem用来存放具体的数据;
- 链接域next用来存放下一个节点的位置(python中的标识);
- 变量p指向链表的头节点(首节点)的位置,从p出发能找到表中的任意节点;
节点实现
class SingleNode(object): """单链表的结点""" def __init__(self,item): # _item存放数据元素 self.item = item # _next是下一个节点的标识 self.next = None
单链表的操作
- is_empty() 链表是否为空;
- length() 链表长度;
- travel() 遍历整个链表;
- add(item) 链表头部添加元素;
- append(item) 链表尾部添加元素;
- insert(pos, item) 指定位置添加元素;
- remove(item) 删除节点;
- search(item) 查找节点是否存在;
class SingleLinkList(object): """单链表""" def __init__(self): self._head = None def is_empty(self): """判断链表是否为空""" return self._head == None def length(self): """链表长度""" # cur初始时指向头节点 cur = self._head count = 0 # 尾节点指向None,当未到达尾部时 while cur != None: count += 1 # 将cur后移一个节点 cur = cur.next return count def travel(self): """遍历链表""" cur = self._head while cur != None: print (cur.item) cur = cur.next def add(self, item): """头部添加元素""" # 先创建一个保存item值的节点 node = SingleNode(item) # 将新节点的链接域next指向头节点,即_head指向的位置 node.next = self._head # 将链表的头_head指向新节点 self._head = node def append(self, item): """尾部添加元素""" node = SingleNode(item) # 先判断链表是否为空,若是空链表,则将_head指向新节点 if self.is_empty(): self._head = node # 若不为空,则找到尾部,将尾节点的next指向新节点 else: cur = self._head while cur.next != None: cur = cur.next cur.next = node def insert(self, pos, item): """指定位置添加元素""" # 若指定位置pos为第一个元素之前,则执行头部插入 if pos <= 0: self.add(item) # 若指定位置超过链表尾部,则执行尾部插入 elif pos > (self.length()-1): self.append(item) # 找到指定位置 else: node = SingleNode(item) count = 0 # pre用来指向指定位置pos的前一个位置pos-1,初始从头节点开始移动到指定位置 pre = self._head while count < (pos-1): count += 1 pre = pre.next # 先将新节点node的next指向插入位置的节点 node.next = pre.next # 将插入位置的前一个节点的next指向新节点 pre.next = node def remove(self,item): """删除节点""" cur = self._head pre = None while cur != None: # 找到了指定元素 if cur.item == item: # 如果第一个就是删除的节点 if not pre: # 将头指针指向头节点的后一个节点 self._head = cur.next else: # 将删除位置前一个节点的next指向删除位置的后一个节点 pre.next = cur.next break else: # 继续按链表后移节点 pre = cur cur = cur.next def search(self,item): """链表查找节点是否存在,并返回True或者False""" cur = self._head while cur != None: if cur.item == item: return True cur = cur.next return False if __name__ == "__main__": ll = SingleLinkList() ll.add(1) ll.add(2) ll.append(3) ll.insert(2, 4) print "length:",ll.length() ll.travel() print ll.search(3) print ll.search(5) ll.remove(1) print "length:",ll.length() ll.travel()
二、LeetCode相关题目
2. 两数之和
题意:给出两个非空的链表用来表示两个非负的整数。其中,它们的各自的位数是按照逆序方式存储的,并且它们的每个节点只能存储一位数字,如果我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。你可以假设出了数字0之外,这两个数都不会以0开头。
思路:此题为链表的基础题,给出的l1,l2两个链表表示的位数按照逆序排序,计算两个列表的和就和笔算两个数字的加法原理一样,首先计算个位,把计算的个位数存储,十位数进行进位;当下一个循环时,把上次的进位和这次一起计算,以此类推,直到给出的两个链表全部计算完。
# Definition for singly-linked list. # class ListNode(object): # def __init__(self, x): # self.val = x # self.next = None class Solution(object): def addTwoNumbers(self, l1, l2): """ :type l1: ListNode :type l2: ListNode :rtype: ListNode """ temp = ListNode(0) l3 = temp a = 0 #当l1不为空或者l2不为空或者a不等于0的时候 while l1 != None or l2 !=None or a != 0: if l1 : #a等于a加上l1当前的值 a += l1.val #l1的指针指向下一个 l1 = l1.next if l2 : a += l2.val l2 = l2.next #temp的下一个的值就是 a%10 temp.next = ListNode(a%10) temp = temp.next a=a//10 #l3代替temp来输出链表 return l3.next
19. 删除链表的倒数第N个节点
题意:给定一个链表,删除链表的倒数第n个节点,并返回链表的头结点。
思路:1.遍历两遍,第一遍计算此列表一共有多少个节点,第二遍删除第n个节点;
2.定义两个指针,两个指针相差n个节点,当后面的指针遍历完整个链表时,删除前面指针的节点。
思路一:
思路二:
class Solution: def removeNthFromEnd(self, head, n): """ :type head: ListNode :type n: int :rtype: ListNode """ p = q = head for i in range(n): q = q.next # 前面的指针先移动n个节点 if not q: # 如果移动n次正好是None,则说明次链表的长度就为n,应该直接去掉头结点 return head.next while q.next: p = p.next q = q.next p.next = p.next.next return head
21. 合并两个有序链表
题意:将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成;
思路:此题为列表操作的基本题目,只需要比较两个列表当前节点元素哪个更小,加入到定义好的链表中并向后移动指针;
class Solution: def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode: head = p = ListNode(-1) # 任意定义一个头结点 while l1 and l2: # 比较l1和l2节点元素的大小,小的节点加入到head节点中,并移动指针 if l1.val < l2.val: p.next = l1 l1 = l1.next else: p.next = l2 l2 = l2.next p = p.next p.next = l1 if l1 else l2 return head.next
23. 合并K个排序链表
题意:合并k个排序链表,返回合并后的排序链表。请分析和描述算法的复杂度;
思路:1. 暴力法,遍历所有链表,获得所有元素,将元素排序后,依次放在链表中;
2.逐一比较,比较k个节点的元素,获得最小值,添加到创建链表的最后;
思路一:
class Solution(object): def mergeKLists(self, lists): """ :type lists: List[ListNode] :rtype: ListNode """ nodes = [] head = point = ListNode(0) for l in lists: while l: nodes.append(l.val) l = l.next for x in sorted(nodes): point.next = ListNode(x) point = point.next return head.next
时间复杂度:O(NlogN),其中N是节点的总数目;
空间复杂度:O(N)。
思路二:
24. 两两交换链表中的节点
题意:给定一个链表,两两交换其中相邻的节点,并返回交换后的节点。
思路:
class Solution: def swapPairs(self, head: ListNode) -> ListNode: dummy = p = ListNode(-1) p.next = head while p.next and p.next.next: a, b = p.next, p.next.next p.next = b a.next = b.next b.next = a p = a return dummy.next
25. K个一组翻转链表
原文地址:https://www.cnblogs.com/ffjsls/p/11000528.html