Python算法题集_回文链表

 Python算法题集_回文链表

  • 题234:回文链表
  • 1. 示例说明
  • 2. 题目解析
    • - 题意分解
    • - 优化思路
    • - 测量工具
  • 3. 代码展开
    • 1) 标准求解【列表检测】
    • 2) 改进版一【堆栈检测】
    • 3) 改进版二【双指针】
  • 4. 最优算法

本文为Python算法题集之一的代码示例

题234:回文链表

1. 示例说明

  • 给你一个单链表的头节点 head ,请你判断该链表是否为回文链表。如果是,返回 true ;否则,返回 false

    示例 1:

    img

    输入:head = [1,2,2,1]
    输出:true
    

    示例 2:

    img

    输入:head = [1,2]
    输出:false
    

    提示:

    • 链表中节点数目在范围[1, 105]
    • 0 <= Node.val <= 9

    **进阶:**你能否用 O(n) 时间复杂度和 O(1) 空间复杂度解决此题?


2. 题目解析

- 题意分解

  1. 本题为链表的值检查
  2. 本题的主要计算有2处,1是链表遍历,2是值比较
  3. 基本的解法是单层循环,读取链表数据后进行检测,所以基本的时间算法复杂度为O(n)

- 优化思路

  1. 通常优化:减少循环层次

  2. 通常优化:增加分支,减少计算集

  3. 通常优化:采用内置算法来提升计算速度

  4. 分析题目特点,分析最优解

    1. 链表需要遍历才能有结果,顺序、倒序检测均可以使用列表list

    2. 空间复杂度为O(1)的算法,一般是需要用到双指针


- 测量工具

  • 本地化测试说明:LeetCode网站测试运行时数据波动很大,因此需要本地化测试解决这个问题
    • CheckFuncPerf(本地化函数用时和内存占用测试模块)已上传到CSDN,地址:Python算法题集_检测函数用时和内存占用的模块
    • 本题很难超时,本地化超时测试用例自己生成,详见【最优算法章节】

3. 代码展开

1) 标准求解【列表检测】

列表的反转使用内置写法,因此效率不错

表现优良,超过88Python算法题集_回文链表_第1张图片

import CheckFuncPerf as cfp

def isPalindrome_base(head):
 if not head:
     return True
 listvals = []
 while head:
     listvals.append(head.val)
     head = head.next
 return listvals == listvals[::-1]

result = cfp.getTimeMemoryStr(isPalindrome_base, head1)
print(result['msg'], '执行结果 = {}'.format(result['result']))

# 运行结果
函数 isPalindrome_base 的运行时间为 75.02 ms;内存使用量为 768.00 KB 执行结果 = True

2) 改进版一【堆栈检测】

堆栈法通常有不错的性能表现,但在列表的内置反转前面败下阵来

表现优良,超过80%Python算法题集_回文链表_第2张图片

import CheckFuncPerf as cfp

def isPalindrome_ext1( head):
 if not head:
     return True
 listvals = []
 icurpos = head
 while icurpos:
     listvals.append(icurpos)
     icurpos = icurpos.next
 istartnode = head
 while listvals:
     nodestack = listvals.pop()
     if istartnode.val == nodestack.val:
         istartnode = istartnode.next
     elif istartnode.val != nodestack.val:
         return False
 return True

result = cfp.getTimeMemoryStr(isPalindrome_ext1, head1)
print(result['msg'], '执行结果 = {}'.format(result['result']))

# 运行结果
函数 isPalindrome_ext1 的运行时间为 166.05 ms;内存使用量为 36.00 KB 执行结果 = True

3) 改进版二【双指针】

没有很多内存分配的事项,空间复杂度好的算法,时间复杂度也很好
表现优异,超过94%Python算法题集_回文链表_第3张图片

import CheckFuncPerf as cfp

def isPalindrome_ext2( head):
 if not head:
     return True
 fastnode, slownode = head, head
 while fastnode and fastnode.next:
     fastnode = fastnode.next.next
     slownode = slownode.next
 if fastnode:
     slownode = slownode.next
 prenode, curnode = None, slownode
 while curnode:
     next_node = curnode.next
     curnode.next = prenode
     prenode = curnode
     curnode = next_node
 while prenode and head:
     if prenode.val == head.val:
         prenode = prenode.next
         head = head.next
     else:
         return False
 return True

result = cfp.getTimeMemoryStr(isPalindrome_ext2, head1)
print(result['msg'], '执行结果 = {}'.format(result['result']))

# 运行结果
函数 isPalindrome_ext2 的运行时间为 112.03 ms;内存使用量为 0.00 KB 执行结果 = True

4. 最优算法

根据本地日志分析,最优算法为第1种isPalindrome_base

nums1 = [x for x in range(200000)]
nums2 = nums1.copy()
nums2.sort(reverse=True)
def generateOneLinkedList(data):
    head = ListNode(-100)
    current_node = head
    for num in data:
        new_node = ListNode(num)
        current_node.next = new_node
        current_node = new_node
    return head.next, new_node
head1, tail1 = generateOneLinkedList(nums1)
head2, tail2 = generateOneLinkedList(nums2)
tail1.next = head2
result = cfp.getTimeMemoryStr(isPalindrome_base, head1)
print(result['msg'], '执行结果 = {}'.format(result['result']))

# 算法本地速度实测比较
函数 isPalindrome_base 的运行时间为 75.02 ms;内存使用量为 768.00 KB 执行结果 = True
函数 isPalindrome_ext1 的运行时间为 166.05 ms;内存使用量为 36.00 KB 执行结果 = True
函数 isPalindrome_ext2 的运行时间为 112.03 ms;内存使用量为 0.00 KB 执行结果 = True

一日练,一日功,一日不练十日空

may the odds be ever in your favor ~

你可能感兴趣的:(算法,链表,数据结构,python,leetcode)