leetcode_day3_筑基期_《绝境求生》

22 阅读7分钟

目录


前言

提示:对环境必须筛选挑剔,否则必然潜移默化的被周边的价值观和各种微小习惯拉下水,拒绝的越早,越容易独善其身。纠缠的时间越长摆脱的阻力越大,甚至没有意识到要摆脱,那就彻底没救了。

本系列《绝境求生》记录转码算法筑基过程,以代码随想录为纲学习,leetcode_hot_100练手,在此记录思考过程,方便过后复现。内容比较粗糙仅便于笔者厘清思路,复盘总结。

我突然觉得前两篇文章模型不够规范。我在努力想一个万能的解题模型
比如:
简单理解?
能不能用图示意?
初始化条件?
边界条件?
用什么方法:暴力法/ 其它巧妙的优化法。
巧妙方法的子思路是?
。。。。。??
细节?
之前见过但没注意到的?
新知识?


提示:以下是本篇文章正文内容

一、206 反转链表

1.模型

简单理解?

把head变成tail, tail变成head

能不能用图示意?

​编辑

 [pre(None)->cur(1)->temp(2)->3->None] 

初始化条件?

解决函数里,cur=head,pre=None, 最后返回pre

边界条件?

只有一层循环
知道while 这个行为本身不会改变cur,只是在不停地判断cur是否为None

用什么方法:暴力法/ 其它巧妙的方法。         巧妙方法的子思路是?         。。。。。??

双指针法 当前指针cur和前一个节点指针pre

"""
把tail变成head
初始化 cur指向next,pre为null,然后把cur用temp存放一下,然后让cur.next指向pre,循环这个过程
双指针法 前一个节点pre 和当前节点 cur
指针题模版:定义节点,列表转链表,画链表图 cur(1)head->2->3->None,初始化指针节点
"""
class ListNode:
    def __init__(self,val=0,next=None):
        self.val=val
        self.next=next
def create_link_list(list):
    if not list:
        return None
    head=ListNode(list[0])
    cur=head
    for val in list[1:]:  #给创造下一个节点,需要新的值,再用cur.next存放下一个节点。再用cur=cur.next串联下一个节点
        cur.next=List[val]
        cur=cur.next
    return head
class solution:
    def reverselist(self,head:ListNode)->ListNode:
        #初始化双指针
        cur=head
        pre=None
        while cur:  #只要cur不为None 就说明还有节点没有处理继续循环
            temp=cur.next  #保存cur的下一个节点(因为等下要改cur.next,会丢地址),当前cur=1,cur.next=2,等一下cur.next=pre 就找不到2了  [pre(None)->cur(1)->temp(2)->3->None]
            #反转当前节点的指向
            cur.next=pre
            #指向完后 要移动位置 pre和cur都要往前走
            pre=cur
            cur=temp
        return pre #循环结束,返回新的头节点

细节?

None

之前见过但没注意到的?

伪代码或者是数据流动图中的null,在python中就是None。

疑惑点/新知识 ?

链表的反转感觉就是再改指针指向

while cur 本质上是判断条件,不是更新操作 ?

  • 它只检查当前的 cur 是不是 None:如果 cur 指向一个节点(非空),就执行循环体;如果 cur 是 None(没节点了),就退出循环。
  • 它不会主动改变 cur 的值

cur是怎么推进的 ?

pre=cur
cur=temp   # 因为之前用temp=cur.next

二、234 回文链表

题目描述

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

示例

  • 示例 1:输入:head = [1,2,2,1] → 输出:true(链表反转后和原链表一致)
  • 示例 2:输入:head = [1,2] → 输出:false(反转后是 [2,1],和原链表不一致)

提示

  • 链表中节点数目在范围 [1, 10^5] 内
  • 节点值范围 [0, 9]
  • 进阶:能否用 O (n) 时间复杂度和 O (1) 空间复杂度解决?

1.模型

简单理解?

就是看起来这个链表是前后对称的

能不能用图示意?

None

初始化条件?

None

边界条件?

None

用什么方法:暴力法/ 其它巧妙的方法。         巧妙方法的子思路是?         。。。。。??

暴力法

列表虽然不能用索引访问,我们就用数组来存链表的值 再用相向双指针来判断数组的值一不一样 就可以知道是不是回文数组。

缺点:需要额为数组存储,时间复杂度是 链表的长度  On

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def isPalindrome(self, head: Optional[ListNode]) -> bool:
        cur=head
        l=[]
        while cur:
            l.append(cur.val)
            cur=cur.next
        left,right=0,len(l)-1
        while left<right:
            if l[right]==l[left]:
                left+=1
                right-=1
            else:
                return False
        return True

优化法

先用快慢指针找到中点,然后用反转链表法把后半段链表反转,然后对比前后两段是不是一样的

class Solution:
    def isPalindrome(self, head: ListNode) -> bool:
        # 如果链表只有一个元素head.next = None 或者为空 那它就是回文链表
        if not head or not head.next:
            return True
        # 1用快慢指针找链表中点(慢指针最终指向中点前一个节点)
        slow = head  # 慢指针:每次走1步
        fast = head  # 快指针:每次走2步
        while fast.next and fast.next.next:  # 快指针能走2步时才继续
            slow = slow.next  # 慢指针走1步
            fast = fast.next.next  # 快指针走2步
        # 2反转后半段链表(从slow.next开始反转)
        # 反转函数(和之前学的双指针反转链表一致)
        def reverselist(self,head:ListNode)->ListNode:
        #初始化双指针
            cur=head
            pre=None
            while cur:  #只要cur不为None 就说明还有节点没有处理继续循环
                temp=cur.next  #保存cur的下一个节点(因为等下要改cur.next,会丢地址),当前cur=1,cur.next=2,等一下cur.next=pre 就找不到2了  [pre(None)->cur(1)->temp(2)->3->None]
            #反转当前节点的指向
                cur.next=pre
            #指向完后 要移动位置 pre和cur都要往前走
                pre=cur
                cur=temp
            return pre #循环结束,返回新的头节点
        #buer 这对吗 我刚做这道题啊 爽用

        reversed_half = reverselist(slow.next)  # 反转后半段,得到新表头
        # 3对比前半段和反转后的后半段
        p1 = head  # p1:前半段的指针(从表头开始)
        p2 = reversed_half  # p2:反转后半段的指针(从反转后的表头开始)
        result = True  # 先假设是回文,后续对比失败再改
        while p2:  # 只要p2不为空(后半段没对比完)
            if p1.val != p2.val:  # 对应值不相等,不是回文
                result = False
                break
            p1 = p1.next  # p1前进
            p2 = p2.next  # p2前进
        # 4多做一步。恢复原链表   因为刚刚不是修改了原来的链表了吗
        slow.next = reverselist(reversed_half)
        
        return result

细节?

忘记cur的形状 任何都可以替代cur 不要学太死,可以用slow fast替代cur

之前见过但没注意到的?

只有要用列表构建链表的时候才用到 cur.next=ListNode(val)    val=1,2,3,.....n
题目给的模式head本身就是个链表不需要再构建

   疑惑点/新知识?

如果链表只有一个元素head.next = None 或者为空 那它就是回文链表

if not head or not head.next:
    return True

快指针走两步,慢指针走一步。快指针走到头退出循环的时候这时候的慢指针指向的就是终点

``

  • 链表 [1→2→2→1](偶数情况):

    • 初始:slow=1,fast=1
    • 第一次循环:slow=2,fast=2(fast.next=1,fast.next.next=None → 循环结束)
    • 最终:slow=2(中点前一个节点),后半段从 slow.next=2 开始
  • 链表 [1→2→3→2→1](奇数情况):

    • 初始:slow=1,fast=1
    • 第一次循环:slow=2,fast=3(fast.next=2,fast.next.next=1 → 继续)
    • 第二次循环:slow=3,fast=1(fast.next=None → 循环结束)
    • 最终:slow=3(中点节点),后半段从 slow.next=2 开始(跳过中点,不影响回文判断)

​编辑

最近沉迷ai   suanming,该说不说给我整高潮了,我要继续努力~