LeetCode50天刷题计划第二季(Day 3 — 解码方法、反转链表 II(16.00-18.30)

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

冲!

一、题目

解码方法

一条包含字母 A-Z 的消息通过以下映射进行了 编码 :

‘A’ -> “1”
‘B’ -> “2”

‘Z’ -> “26”
要 解码 已编码的消息,所有数字必须基于上述映射的方法,反向映射回字母(可能有多种方法)。例如,“11106” 可以映射为:

“AAJF” ,将消息分组为 (1 1 10 6)
“KJF” ,将消息分组为 (11 10 6)
注意,消息不能分组为 (1 11 06) ,因为 “06” 不能映射为 “F” ,这是由于 “6” 和 “06” 在映射中并不等价。

给你一个只含数字的 非空 字符串 s ,请计算并返回 解码 方法的 总数 。

题目数据保证答案肯定是一个 32 位 的整数。

示例

示例 1:
输入:s = “12”
输出:2
解释:它可以解码为 “AB”(1 2)或者 “L”(12)。

示例 2:
输入:s = “226”
输出:3
解释:它可以解码为 “BZ” (2 26), “VF” (22 6), 或者 “BBF” (2 2 6) 。

示例 3:
输入:s = “0”
输出:0
解释:没有字符映射到以 0 开头的数字。
含有 0 的有效映射是 ‘J’ -> “10” 和 ‘T’-> “20” 。
由于没有字符,因此没有有效的方法对此进行解码,因为所有数字都需要映射。

提示

1 <= s.length <= 100
s 只包含数字,并且可能包含前导零。

二、思路

这道题一看就被唬住了,完全没有一点思路,感觉数字串太长了,不知道怎么挨个组合才能不遗漏。事实上所有涉及大问题的题都可以转化为小问题来求解,即动态规划(也可以叫做“递推”)。

对于一个字符串来说,遍历每一个字母都会产生两种情况,①将这个字母i单独翻译,fi=f(i-1)(需要该字母!=0)②将这个字母和他前面的字母一起翻译(需要两个数的值属于【1,26】)将这两种情况的和加起来就是当前字母的情况了~

根据这个思路,我们再来规划一下初始值,对于第一个字母,需要求f0的值,其值需要依靠f(-1)和f(-2),第二种显然不可能,因此直接根据s(1)是否为0可以判断出f(0)的值,f(-1)直接赋值1(根据f(2)的计算)

有了初始值和状态转移方程,剩下的就很好办了,为了优化存储空间,每次保留相邻三个数据即可~

三、代码

class Solution:
    def numDecodings(self, s: str) -> int:
        f=[0,0] #记录当前需要计算的数的前面两个数据(f(i-2)、(f(i-1))
        f[0]=1 #f(-1)
        if(s[0] == '0'): #f(0)
            f[1]=0
        else:
            f[1]=1
        for i in range(1,len(s)):
            if(s[i] !='0'): #①
                temp1=f[1]
            else:
                temp1=0
            temp=int(s[i-1:i+1])
            if(s[i-1]!='0' and temp>=1 and temp<=26 ): #②
                temp2=f[0]
            else:
                temp2=0
            f[0]=f[1]
            f[1]=temp1+temp2
        return f[1]

四、题目

反转链表 II

给你单链表的头指针 head 和两个整数 left 和 right ,其中 left <= right 。请你反转从位置 left 到位置 right 的链表节点,返回反转后的链表 。

示例

示例 1:
输入:head = [1,2,3,4,5], left = 2, right = 4
输出:[1,4,3,2,5]

示例 2:
输入:head = [5], left = 1, right = 1
输出:[5]

提示:

链表中节点数目为 n
1 <= n <= 500
-500 <= Node.val <= 500
1 <= left <= right <= n

进阶:

你可以使用一趟扫描完成反转吗?

五、思路

首先把指针移动到left前的位置,找到不用翻转的最后的尾巴,为了防止第一个元素就是left,需要补一个虚表头
然后反转链表至少需要三个指针,部署三个指针,使中间那个指针指向left元素,然后不断反转后移直到right,
都反转完之后把断点处处理一下就可以了!

六、代码

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def reverseBetween(self, head: Optional[ListNode], left: int, right: int) -> Optional[ListNode]:
       
        Head=ListNode(0,head)
        left=left-1
        right=right-1
        i=-1 #计数
        keyrear=Head #不用翻转的最后的尾巴
        while(i<left-1): #把指针移动到left前的位置
            keyrear=keyrear.next
            i+=1
        keystart=keyrear.next 
        p1=keyrear.next #指针1,初始指向left
        if(p1 != None):
            p2=p1.next #指针2
        else:
            p2=None
        if(p2 != None):
            p3=p2.next
        i+=2
        #开始翻转
        while(i<=right): #开始翻转
            p2.next=p1
            p1=p2
            p2=p3
            if(p3 != None):
                p3=p3.next
            i+=1
        #连接
        keyrear.next=p1
        if(keystart != None):
            keystart.next=p2
        return Head.next






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值