Task02 顺序表和链表
理论部分
理解线性表的定义与操作。
实现顺序表。
实现单链表、循环链表、双向链表。
练习部分
1、合并两个有序链表
将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例:
输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4
方法1 递归
思路:若l1和l2中两个都为null,则返回None,若其中一个为空,则返回另一个链表。之后先比较两个链表的头元素,看哪一个更小,递归地决定下一个添加到结果里的值。
1、基线条件(告诉函数不再调用自己,即递归如何终止,避免无限循环):
if l1=null:return l2
if l2 = null:return l1
2、递归条件(函数调用自己):
if l1.val < l2.val:
l1.next = self.mergeTwoLists(l1.next, l2)
return l1
if l1.val >= l2.val:
l2.next = self.mergeTwoLists(l2.next, l1)
return l2
3、递归过程:输入:l1:1->2->4, l2:1->3->4
step 1:l1:1->2->4, l2:1->3->4 --> l2.next=self.mergeTwoLists(3->4,1->2->4 )
step 2:l1:1->2->4, l2:3->4 --> l1.next=self.mergeTwoLists(2->4,3->4 )
step 3:l1:2->4, l2:3->4 --> l1.next=self.mergeTwoLists(4,3->4 )
step 4:l1:4, l2:3->4 --> l2.next=self.mergeTwoLists(4,4)
step 5:l1:4, l2:4 --> l2.next=self.mergeTwoLists(4,null)
step 6:l1:4, l2:null -->return 4
step 5:l1:4, l2:4 --> l2.next=self.mergeTwoLists(4,null) -->return 4->4
step 4:l1:4, l2:3->4 --> l2.next=self.mergeTwoLists(4,4) -->return 3->4->4
step 3:l1:2->4, l2:3->4 --> l1.next=self.mergeTwoLists(4,3->4 ) -->return 2->3->4->4
step 2:l1:1->2->4, l2:3->4 --> l1.next=self.mergeTwoLists(2->4,3->4 )-->return 1->2->3->4->4
step 1:l1:1->2->4, l2:1->3->4 --> l2.next=self.mergeTwoLists(3->4,1->2->4 )-->return 1->1->2->3->4->4
def mergetwoLists(self, l1, l2):
if l1 is None:
return l2
elif l2 is None:
return l1
elif l1.val < l2.val:
l1.next = self.mergeTwoLists(l1.next, l2)
return l1
else:
l2.next = self.mergeTwoLists(l1, l2.next)
return l2
方法2 迭代
建立一个虚拟节点:prehead,维护指针prev。比较l1和l2的头元素,将头元素更小的链表l1接在prev.next,prev指针后移一个单位,再用新的l1=l1.next与l2比较,以此类推,直到l1和l2其中一个链表为空,将不空的那个链表接到pre.next
class Solution(object):
def mergeTwoLists(self, l1, l2):
prehead = ListNode(-1)
prev = prehead
while l1 and l2:
if l1.val <= l2.val:
prev.next = l1
l1 = l1.next
else:
prev.next = l2
l2 = l2.next
prev = prev.next
prev.next = l1 if l1 is not None else l2
return prehead.next
2、删除链表的倒数第N个节点
给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。
示例:
给定一个链表: 1->2->3->4->5, 和 n = 2.
当删除了倒数第二个节点后,链表变为 1->2->3->5.
方法1:二次遍历实现
一次遍历,求出链表的总长度k。
二次遍历,根据总长度k的值,求出k-n,将k-n的指针指向k-n+2,就将k-n+1的节点删除了
def removeNthFromEnd(self, head, n):
if not head or n<=0: #链表为空或者n无效
return head
p = ListNode(-1) #建造一个虚拟节点,方便边界处理
p.next = head
#一次遍历得到链表长度
a = p
k = 0
while a.next:
a = a.next
k = k+1
if k<n: #n无效
return head
#二次遍历找到需要删除的节点
b = p
num = k-n #需删除的前一个节点位置
while num > 0:
b = b.next
num = num-1
b.next = b.next.next #将指针指向删除节点的后一位
return p.next
方法2:一次遍历实现
设置两个指针a和b,第一个指针b先走n步,然后a和b再同时走,b走到终点的时候,a就到被删除节点的前一位了。然后同方法一。
class Solution(object):
def removeNthFromEnd(self, head, n):
p = ListNode(-1)
p.next = head
a = p
b = p
while n: #b先走n步
b = b.next
n = n-1
if not b: #若n>链表长度,那么迭代n次后,b肯定为空
return head
while b.next:
a = a.next
b = b.next
a.next = a.next.next
return p.next
3、旋转链表
给定一个链表,旋转链表,将链表每个节点向右移动k个位置,其中k是非负数。
示例 1:
输入: 1->2->3->4->5->NULL, k = 2
输出: 4->5->1->2->3->NULL
解释:
向右旋转 1 步: 5->1->2->3->4->NULL
向右旋转 2 步: 4->5->1->2->3->NULL
示例 2:
输入: 0->1->2->NULL, k = 4
输出: 2->0->1->NULL
解释:
向右旋转 1 步: 2->0->1->NULL
向右旋转 2 步: 1->2->0->NULL
向右旋转 3 步: 0->1->2->NULL
向右旋转 4 步: 2->0->1->NULL
思路:
其实跟题目2有相似之处,即找到新的头结点和尾结点的位置,设链表长度为n,若k>n,则相当于右移 k%n 步。先计算链表长度。再将链表连接成环状,即用就得尾结点指向旧的头结点。之后计算新的新的头结点和尾结点,确定后在尾结点处切断,指向None即可。
def rotateRight(self, head, k):
if not head:
return None
if not head.next:
return head
old_tail = head
n = 1
while old_tail.next: #计算链表长度
old_tail = old_tail.next
n = n+1
old_tail.next = head #构造成环状
new_tail = head
m = n - k % n -1
while m:
new_tail = new_tail.next #新的尾结点的位置
m = m-1
new_head = new_tail.next #新的头结点的位置
new_tail.next = None #切断这个环
return new_head