欢迎关注微信公众号:简说Python
关注后回复:1024,可以领取精选编程学习电子书籍。
这两天和几个朋友组了个互相督促学习群,想着督促一下自己学习,也督促自己的原创输出,其实很多时候都是懒,真不是没有东西可以写了,这不,我在我的免费知识星球简说编程
里开了个新的标签日常编程问题
,后面我会把自己学习工作中遇到的一些问题和解决方法记录到里面,有些可以扩展的点,我会写到微信公众号里。
我定的目标是:
我简单写了个规则,大家说可以,然后,我们就开始吧,我习惯把该做的事情提前一天做(如果有时间的话)。
今天给大家分享的书籍《Python程序员面试算法宝典》第一章第八节:翻转链表k个相邻结点。
如果你是第一次看,也许,你可以看看本系列下面的文章:
Smaller And Smarter Python数据结构:链表逆转
Smaller And Smarter Python数据结构:删除无序链表重复结点
Smaller And Smarter Python数据结构:链表相加
Smaller And Smarter Python数据结构:链表进行重新排序
Smaller And Smarter Python数据结构:链表倒数第K个元素+检测单链表环
Smaller And Smarter Python数据结构:翻转链表相邻结点
"""
目标:写一段程序,k个为一组翻转链表相邻结点
例如:
输入 k = 3
输入-> 1->2->3->4->5->6->7
输出-> 3->2->1->6->5->4->7
Goal: write a program, K for a group of adjacent nodes of flip list
For example:
Input k = 3
Input - > 1 - > 2 - > 3 - > 4 - > 5 - > 6 - > 7
Output - > 3 - > 2 - > 1 - > 6 - > 5 - > 4 - > 7
"""
首先我们写好链表的基本操作,在a_0_base.py
文件中,目前包含对链表的定义类,初始化函数,遍历函数。(带头结点)
# -*- coding: utf-8 -*-
"""
@author = 老表
@date = 2019-10-19
@个人微信公众号 : 简说Python
"""
# 链表数据结构定义
class ListNode:
def __init__(self, x):
self.data = x
self.next = None
class ListOperation:
a = 1
# 根据链表数据初始化链表
@staticmethod
def init_list(n_list):
# 初始化一个头指针
head = ListNode("head")
cur = head
for i in n_list:
node = ListNode(i)
cur.next = node
cur = node # 相当于 cur = cur.next,后移
return head
# 根据链表数据初始化一个有环的链表
@staticmethod
def init_ring_list(n_list):
# 初始化一个头指针
head = ListNode("head")
cur = head
for i in n_list:
node = ListNode(i)
cur.next = node
cur = node # 相当于 cur = cur.next,后移
cur.next = head.next.next.next.next # 随意的,让最后一个结点指向第四个结点
return head
# 遍历链表
@staticmethod
def ergodic_list(head):
# print(head.data)
cur = head.next
while cur:
print(cur.data)
cur = cur.next
# 获取链表长度
@staticmethod
def get_len_list(head):
cur = head.next
len_list = 0
while cur:
len_list = len_list + 1
cur = cur.next
return len_list
开始程序前需提前导入前面写好的链表基本操作包和结点数据结构,在Linked_list的a_0_base.py
中。
from Linked_list.a_0_base import ListOperation
"""
Method One : 分组逆转法
核心思想:以k个结点为一组,每组看作一个子链表,
逆转每个子链表,然后让逆转后的最后一个结点指向
下一组,继续逆转,直到结束。
时间复杂度:O(N)
空间复杂度:O(1)
"""
'''
在做 链表重新排序 时,我们就已经写个这个函数
'''
# 辅助函数:不带头结点链表逆转
def reverse_list(l1):
if not l1 or not l1.next: # 空链表或只有一个结点
return l1
cur_node = l1.next # 记录当前结点
pre_node = l1 # 记录前驱结点
l1.next = None # 设置尾结点
while cur_node:
next_node = cur_node.next # 记录后继结点
cur_node.next = pre_node # 当前结点反向指向前驱结点
pre_node = cur_node # 前驱结点后移
cur_node = next_node # 后移遍历
return pre_node # 返回逆转后的第一个结点
def flip_k_node_one(head, k):
if not head.next:
# 空链表
return head
# 返回头结点
pre_node = head
# 记录前驱结点
begin_node = head.next
# 记录每组开始结点
while begin_node:
# 遍历分组逆转,连接
i = 1
# 分组标记 i < k
end_node = begin_node
# 记录每组尾结点
while i < k:
# 遍历找到每组尾结点
if end_node.next:
end_node = end_node.next
else:
return head
# 剩余结点不足k个结点,说明分组转换完成
i = i + 1
# 标记值后移
# print("222222", i)
next_node = end_node.next
# 记录下一组开始结点
end_node.next = None
# 断开前一组与后一组的链接
pre_node.next = reverse_list(begin_node)
# 逆转前一组的子链,返回逆转后的表尾结点,让开始结点指向该结点
# print(pre_node.next.data)
begin_node.next = next_node
# 前一组逆转好的尾结点指向下一组的第一个结点
pre_node = begin_node
# 前驱结点后移,即成为前一组的尾结点,相当于后一组的头结点
begin_node = next_node
# 开始结点后移,成为后一组的第一个结点
return head # 返回头结点
# 当然,也许还有别的方法,比如建一个辅助的链表
# 欢迎你说出你的想法
# 程序入口,测试函数功能
if __name__ == "__main__":
list_data = [1, 2, 3, 4, 5, 6, 7] # 链表初始化数据
head = ListOperation.init_list(list_data) # 初始化链表,带头结点
ListOperation.ergodic_list(head) # 未操作前,遍历打印链表
len_list = ListOperation.get_len_list(head) # 获取链表长度
k = int(input("请输入参数K in (0, %d] : " % len_list)) # 输入参数k值
while k > len_list: # 基本判断,过滤
print("k值过大,k in (0, %d]" % len_list)
k = int(input("请重新输入参数K:"))
head = flip_k_node_one(head, k) # 测试方法一
print("---------------------")
ListOperation.ergodic_list(head) # 操作后,遍历打印链表
本文代码思路部分来自书籍《Python程序员面试宝典》,书中部分代码有问题或未提供代码,文中已经修改过了,并添加上了丰厚的注释,方便大家学习,后面我会把所有内容开源放到Github上,包括代码,思路,算法图解(手绘或者电脑画),时间充裕的话,会录制视频。
希望大家多多支持。
大家好,我是老表
觉得本文不错的话,转发、留言、点赞,是对我最大的支持。
欢迎关注微信公众号:简说Python
关注后回复:1024,可以领取精选编程学习电子书籍。