leetcode_day2_筑基期_《绝境求生》

24 阅读9分钟

目录


前言

提示:多喝水 突然感觉,如果身材成为了吃饭的工具,那我一定会好好练,坚持练,好好吃,坚持吃。

Workflow:

        Step1

                右屏pycharm写代码

                左屏放代码随想录知识点

                中屏一分为二查资料and放csdn富文编辑器

        Step2

                把右屏pycharm笔记复制到csdn富文编辑器

                排版csdn

        备注:

                图片可以连平板直接huawei文件夹拖拽

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

一级标题为题目,后跟输入输出示例。
二级标题为模型(解题的几种方法)


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

一、160链表相交

链表定义        

        链表是一种通过指针串联在一起的线性结构,每个部分包括数据域和指针两个东西,注意head和tail,tail后面是Null
链表的类型:单链表,双链表,循环链表。 想一想长什么样

链表的特性和数组的特性对比:

​编辑

链表的定义_python
class ListNode:

        def init(self, val=0, next=None):

                self.val=val

                self.next=next

示例

给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null 。

图示两个链表在节点 c1 开始相交:

​编辑

题目数据 保证 整个链式结构中不存在环。
注意,函数返回结果后,链表必须 保持其原始结构 。
​编辑

模型

怎么构造节点?
节点是怎么串联的?
怎么实现在head位置的curA和curB对齐
cur是指当前节点,它有值,有指针 !!记住这个核心  记住下面这张图

构建链表节点
# 第一步:计算两个链表的长度
# 第二步:让B为较长的链表,让较长的链表先走 长度差步,使两个链表末尾对齐
# 第三步:同时遍历两个链表,第一个相同的节点就是相交节点  
# 遍历结束仍未找到,说明不相交  return None

​编辑

笔记和敲的代码集成在一起了,链表这玩意就是手造一个数据结构

# 定义链表节点类  有两个属性:节点的值和next指针,指向后面的节点
'''
ListNode 类:链表的节点构建,每个节点有两个属性:
val:存储具体数据(比如列表里的 1、2、3);
next:指针,指向后面的节点(默认是 None)。
列表 arr:输入数据,比如 [1,2,3],要把它变成 1 -> 2 -> 3 的链表。
'''
class ListNode:  #每次构建一个节点都要调用这个
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next

# 根据列表创建链表    有了前面的构建节点我们才能创建链表
def create_linked_list(arr):
    if not arr:  #列表为空时返回空的链表 arr 是空列表(比如 []),直接返回 None(空链表)
        return None
    head = ListNode(arr[0])   #头节点为链表的起点后续不会改变
    cur = head    #创建游标节点,负责串联后面的节点  ,此时cur和head都指向val=1,next=None
    """
    循环逻辑:每次取列表的一个元素,做两件事:
        用 cur.next 把新节点 “挂” 在当前 cur 后面; 
        让 cur 移动到新节点,为下一次 “挂节点” 做准备。
    """
    for val in arr[1:]:   
        cur.next = ListNode(val)
        cur = cur.next
    return head   # # 最终返回 head,通过 head 就能找到整个链表:1->2->3

# 打印链表(验证链表结构和结果)
def print_linked_list(head):
    res = []
    cur = head
    while cur:
        res.append(str(cur.val))
        cur = cur.next
    print(" -> ".join(res) if res else "空链表")

# 求相交链表的相交节点
class Solution:
    def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
        # 第一步:计算两个链表的长度
        lenA, lenB = 0, 0
        cur = headA
        while cur:  # 遍历链表A,统计长度  
            cur = cur.next
            lenA += 1
        cur = headB
        while cur:  # 遍历链表B,统计长度
            cur = cur.next
            lenB += 1
        
        # 第二步:让B为较长的链表,让较长的链表先走 长度差步,使两个链表末尾对齐
        curA, curB = headA, headB
        if lenA > lenB:  # 确保curB指向较长链表,curA指向较短链表
            curA, curB = curB, curA
            lenA, lenB = lenB, lenA  # 交换长度,保证lenB >= lenA
        
        # 较长链表(curB)先走 lenB - lenA 步,和curA对齐
        for _ in range(lenB - lenA):
            curB = curB.next
        
        # 第三步:同时遍历两个链表,第一个相同的节点就是相交节点
        while curA:
            if curA == curB:  # 注意:是节点地址相同,不是值相同!地址相同值肯定相同
                return curA
            curA = curA.next
            curB = curB.next
        
        # 遍历结束仍未找到,说明不相交
        return None

# ---------------------- 测试代码 ----------------------
if __name__ == "__main__":
    # 场景1:两个链表相交
    # 构造逻辑:A = [1,2,3], B = [4,5], 共同相交部分 = [6,7]
    # 最终链表结构:
    # A: 1 -> 2 -> 3 -> 6 -> 7
    # B:       4 -> 5 -> 6 -> 7  (相交于节点6)
    common = create_linked_list([6,7])  # 构造公共相交部分链表
    headA = create_linked_list([1,2,3]) #构造链表A
    curA = headA
    while curA.next:  # 找到A的末尾,连接公共部分
        curA = curA.next
    curA.next = common  # A的末尾指向公共节点6
    
    headB = create_linked_list([4,5]) #构造链表A
    curB = headB
    while curB.next:  # 找到B的末尾,连接公共部分
        curB = curB.next
    curB.next = common  # B的末尾指向公共节点6
    
    print("测试场景1:链表相交")
    print("链表A:", end="")
    print_linked_list(headA)
    print("链表B:", end="")
    print_linked_list(headB)
    
    solution = Solution()
    intersect_node = solution.getIntersectionNode(headA, headB)
    if intersect_node:
        print(f"相交节点值:{intersect_node.val}")  # 输出:6
    else:
        print("无相交节点")
    
    # 场景2:两个链表不相交(验证边界情况)
    print("\n测试场景2:链表不相交")
    headC = create_linked_list([10,20,30])
    headD = create_linked_list([40,50])
    print("链表C:", end="")      #end是连接下一个print的方式
    print_linked_list(headC)
    print("链表D:", end="")
    print_linked_list(headD)
    
    no_intersect_node = solution.getIntersectionNode(headC, headD)
    if no_intersect_node:
        print(f"相交节点值:{no_intersect_node.val}")
    else:
        print("无相交节点")  # 输出:无相交节点

二、20有效括号

示例 1:

输入: s = "()"

输出: true

示例 2:

输入: s = "()[]{}"

输出: true

示例 3:

输入: s = "(]"

输出: false

示例 4:

输入: s = "([])"

输出: true

示例 5:

输入: s = "([)]"

输出: false

1.模型

"""
细节:用栈(先进后出)来解决,用append 和 pop语法
        从左到右遍历所以肯定是先经过左边的括号,左括号要用相同类型的右括号闭合
操作:
    一旦遇到左括号
        往栈里推进一个右括号, 就是说后面一定会遇到一个match 的右括号pop出来不然就错
    如果遇到右括号
        若栈为空,说明不对,没有相应的左跟它匹配
        若栈不为空,但是栈顶的元素不和右括号相等,说明也不对
        只有栈不为空且栈顶跟右括号长得一样才match 成功,把栈顶pop出来(最终就是空栈的情况)
"""
s='(()){({})}[]'
def Solution(s:str)->bool:
    stack=[]
    for item in s:
        if item=='{':
            stack.append('}')
        elif item=='(':
            stack.append(')')
        elif item=='[':
            stack.append(']')
        #这样就收集好了match左括号的右括号,这时循环开始遍历右括号 我们判断栈顶不相等右括#号还有没遍历完却空栈的情况
        elif not stack or item!=stack[-1]:
             return False
        else:
            stack.pop()
    #遍历完了如果不是空栈 那就是错   比如(()){({})}[  这种情况
    return True if not stack else False
print(Solution(s))

``

三、49字母异位词分组

示例 1:

输入: strs = ["eat", "tea", "tan", "ate", "nat", "bat"]

输出: [["bat"],["nat","tan"],["ate","eat","tea"]]

解释:

  • 在 strs 中没有字符串可以通过重新排列来形成 "bat"
  • 字符串 "nat" 和 "tan" 是字母异位词,因为它们可以重新排列以形成彼此。
  • 字符串 "ate" ,"eat" 和 "tea" 是字母异位词,因为它们可以重新排列以形成彼此。

示例 2:

输入: strs = [""]

输出: [[""]]

示例 3:

输入: strs = ["a"]

输出: [["a"]]

1.模型

'''
哈希表字典法,
任务:把字母相同但是排列不同的字符串分到同一组
用哈希表(字典) 做 “分组容器”:
    键(key):字符串排序后的结果; 
    值(value):存储所有对应这个 key 的异位词(列表形式);
细节:
    细节:一个乱序的字符串是可以通过sorted()排序成有序的a,b,c,d,e,f,g......然后输出为一个列表的这个很关键,再用''.join()变成一个字符串
    需要从数据输出的数据结构反推,从内向外依次为 字符串,包含字符串的列表,包含几个列表的列表。
    要先判断字典里是否有标志,没有则放一个[]才能append item,不然没有容器append
'''
strs = ["eat", "tea", "tan", "ate", "nat","bat"]
#输出:[["bat"],["nat","tan"],["ate","eat","tea"]]
dict={}
def solution(strs):
    dict={}
    for item in strs:
        sorted_item=''.join(sorted(item))   #sorted 一遍完后item是列表,再用''.join()变成字符串  sorted_item作为key
        if sorted_item not in dict:
            dict[sorted_item] = [] 
 #要先判断字典里是否有不是则放一个[]才能写下面这一步,不然没有容器append
        dict[sorted_item].append(item)
        # print(sorted_item)
        #存到字典里,字典可以用append,就是值的位置变成一个列表
    return list(dict.values())  #遍历所有字符串,按排序后的 key 分组,最后返回所有 value 即可。
solution(strs)

遍历过程:
遍历输入字符串数组 strs:
对于第一个字符串 "eat",排序后为 "aet",将它加入到键为 "aet" 的列表中。
对于第二个字符串 "tea",排序后也为 "aet",因此也加入到键为 "aet" 的列表中。
对于第三个字符串 "tan",排序后为 "ant",将它加入到键为 "ant" 的列表中。
对于第四个字符串 "ate",排序后为 "aet",同样加入到键为 "aet" 的列表中。
对于第五个字符串 "nat",排序后为 "ant",同样加入到键为 "ant" 的列表中。
对于最后一个字符串 "bat",排序后为 "abt",将它加入到键为 "abt" 的列表中。
最终,我们得到的 d 字典如下所示:
{
'aet': ['eat', 'tea', 'ate'],
'ant': ['tan', 'nat'],
'abt': ['bat']
}
将 d 字典的所有值转换为列表并返回,即 [['eat', 'tea', 'ate'], ['tan', 'nat'], ['bat']]。

如果你的进攻思路很窄,那说明武器库的东西还不够多